diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..bb7260c
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,57 @@
+# Git
+.git
+.gitignore
+.github
+
+# Python
+__pycache__
+*.py[cod]
+*$py.class
+*.so
+.Python
+*.egg-info
+dist
+build
+*.egg
+
+# Virtual environments
+venv/
+env/
+ENV/
+.venv
+
+# IDE
+.vscode
+.idea
+*.swp
+*.swo
+*~
+
+# Testing
+.pytest_cache
+.coverage
+htmlcov
+.tox
+.nox
+
+# Documentation
+docs/_build
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Project specific
+*.blockchain
+wallets/
+*.key
+*.pem
+logs/
+data/
+*.log
+
+# Development
+*.md
+LICENSE
+.dockerignore
+docker-compose.yml
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..7eb4e51
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,167 @@
+name: Blockchain CI/CD
+
+on:
+ push:
+ branches: [ main, develop, claude/** ]
+ pull_request:
+ branches: [ main, develop ]
+
+jobs:
+ test:
+ name: Test on Python ${{ matrix.python-version }}
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ['3.8', '3.9', '3.10', '3.11']
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v4
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Cache pip packages
+ uses: actions/cache@v3
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ pip install -e .
+
+ - name: Run tests with pytest
+ run: |
+ pytest -v --cov=blockchain_core --cov-report=xml --cov-report=term
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ file: ./coverage.xml
+ flags: unittests
+ name: codecov-umbrella
+ fail_ci_if_error: false
+
+ lint:
+ name: Lint and Format Check
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install flake8 black pylint mypy
+
+ - name: Lint with flake8
+ run: |
+ # Stop the build if there are Python syntax errors or undefined names
+ flake8 blockchain_core --count --select=E9,F63,F7,F82 --show-source --statistics
+ # Exit-zero treats all errors as warnings
+ flake8 blockchain_core --count --exit-zero --max-complexity=10 --max-line-length=120 --statistics
+
+ - name: Check formatting with black
+ run: |
+ black --check blockchain_core tests examples
+
+ - name: Lint with pylint
+ run: |
+ pylint blockchain_core --exit-zero
+
+ - name: Type check with mypy
+ run: |
+ mypy blockchain_core --ignore-missing-imports --no-strict-optional || true
+
+ security:
+ name: Security Check
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install safety bandit
+
+ - name: Check for security vulnerabilities
+ run: |
+ safety check --json || true
+
+ - name: Run bandit security linter
+ run: |
+ bandit -r blockchain_core -f json -o bandit-report.json || true
+
+ - name: Upload bandit report
+ uses: actions/upload-artifact@v3
+ with:
+ name: bandit-security-report
+ path: bandit-report.json
+
+ docker:
+ name: Build Docker Image
+ runs-on: ubuntu-latest
+ needs: [test, lint]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Build Docker image
+ run: |
+ docker build -t blockchain:${{ github.sha }} .
+
+ - name: Test Docker image
+ run: |
+ docker run --rm blockchain:${{ github.sha }} python -c "from blockchain_core import Blockchain; print('Docker build successful!')"
+
+ examples:
+ name: Run Examples
+ runs-on: ubuntu-latest
+ needs: test
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ pip install -r requirements.txt
+ pip install -e .
+
+ - name: Run basic usage example
+ run: |
+ python examples/basic_usage.py
+
+ - name: Run advanced features example
+ run: |
+ python examples/advanced_features.py
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea59735
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,144 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+Pipfile.lock
+
+# PEP 582
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Blockchain specific
+*.blockchain
+wallets/
+*.key
+*.pem
+
+# Logs
+logs/
+*.log
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..98be998
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,100 @@
+# Pre-commit hooks configuration
+# See https://pre-commit.com for more information
+
+repos:
+ # General file checks
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v4.5.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-added-large-files
+ args: ['--maxkb=500']
+ - id: check-json
+ - id: check-toml
+ - id: check-merge-conflict
+ - id: check-case-conflict
+ - id: detect-private-key
+ - id: debug-statements
+ - id: mixed-line-ending
+ - id: fix-byte-order-marker
+
+ # Python code formatting
+ - repo: https://github.com/psf/black
+ rev: 23.12.1
+ hooks:
+ - id: black
+ language_version: python3
+ args: ['--line-length=120']
+
+ # Python import sorting
+ - repo: https://github.com/PyCQA/isort
+ rev: 5.13.2
+ hooks:
+ - id: isort
+ args: ['--profile', 'black', '--line-length', '120']
+
+ # Python linting
+ - repo: https://github.com/PyCQA/flake8
+ rev: 7.0.0
+ hooks:
+ - id: flake8
+ args: ['--max-line-length=120', '--extend-ignore=E203,W503']
+ additional_dependencies: [flake8-docstrings]
+
+ # Security checks
+ - repo: https://github.com/PyCQA/bandit
+ rev: 1.7.6
+ hooks:
+ - id: bandit
+ args: ['-r', 'blockchain_core', '-ll']
+ exclude: tests/
+
+ # Type checking
+ - repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v1.8.0
+ hooks:
+ - id: mypy
+ args: ['--ignore-missing-imports', '--no-strict-optional']
+ additional_dependencies: [types-all]
+
+ # YAML formatting
+ - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
+ rev: v2.12.0
+ hooks:
+ - id: pretty-format-yaml
+ args: ['--autofix', '--indent', '2']
+
+ # Markdown linting
+ - repo: https://github.com/markdownlint/markdownlint
+ rev: v0.12.0
+ hooks:
+ - id: markdownlint
+ args: ['--fix']
+
+ # Dockerfile linting
+ - repo: https://github.com/hadolint/hadolint
+ rev: v2.12.0
+ hooks:
+ - id: hadolint-docker
+
+# Run these hooks on specific file types
+default_language_version:
+ python: python3
+
+# Files to exclude
+exclude: |
+ (?x)^(
+ \.git/|
+ \.pytest_cache/|
+ __pycache__/|
+ \.mypy_cache/|
+ \.eggs/|
+ build/|
+ dist/|
+ .*\.egg-info/|
+ venv/|
+ env/|
+ blockchain\.py\.old
+ )$
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..d6a809f
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,179 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+- REST API with Flask for blockchain operations
+- Database persistence layer with SQLite
+- Merkle tree implementation for efficient transaction verification
+- Performance benchmarking suite
+- Integration tests for end-to-end scenarios
+- Pre-commit hooks configuration
+
+## [1.0.0] - 2024-11-13
+
+### Added
+- Complete blockchain reorganization with modular architecture
+- Modular package structure (`blockchain_core`)
+- Separate modules for blockchain, block, wallet, transaction, and utilities
+- Comprehensive CLI interface using Click
+ - Wallet management (create, load, export)
+ - Mining operations
+ - Transaction creation and validation
+ - Blockchain exploration and validation
+ - Statistics and reporting
+- Full test suite with pytest
+ - Unit tests for all components
+ - Test coverage configuration
+ - 5 comprehensive test modules
+- Enhanced documentation
+ - Rewritten README with detailed examples
+ - Complete API documentation
+ - Code examples (basic and advanced)
+- Docker support
+ - Dockerfile for containerized deployment
+ - docker-compose.yml for development
+ - .dockerignore for optimized builds
+- CI/CD with GitHub Actions
+ - Multi-version Python testing (3.8-3.11)
+ - Linting and code quality checks (flake8, pylint, black)
+ - Security scanning (bandit, safety)
+ - Docker build verification
+ - Example execution tests
+- Configuration management system
+- Professional project structure
+ - setup.py for package installation
+ - requirements.txt with all dependencies
+ - pytest.ini for test configuration
+ - .gitignore for clean repository
+- Type hints throughout codebase
+- Enhanced error handling and logging
+- Comprehensive docstrings for all functions
+
+### Changed
+- Split monolithic blockchain.py into separate, maintainable modules
+- Improved code organization with proper separation of concerns
+- Enhanced security with better validation
+- Improved transaction verification
+- Better balance calculation
+- More robust proof-of-work implementation
+
+### Documentation
+- CONTRIBUTING.md with contribution guidelines
+- CODE_OF_CONDUCT.md for community standards
+- SECURITY.md for security policies
+- Complete API reference in docs/API.md
+- Usage examples in examples/ directory
+
+## [0.1.0] - 2024-10-XX
+
+### Added
+- Initial blockchain implementation
+- Basic Block class
+- Simple Blockchain class with genesis block
+- Wallet class with ECDSA key generation
+- Transaction signing and verification
+- Proof of work consensus
+- Basic balance tracking
+- Simple main function demo
+
+### Features
+- SHA-256 hashing for blocks
+- ECDSA SECP256K1 for cryptographic signatures
+- Configurable mining difficulty
+- Miner rewards
+- Transaction validation
+- Node registration
+
+---
+
+## Version History Summary
+
+### [1.0.0] - Major Release
+- Complete rewrite and reorganization
+- Production-ready with comprehensive testing
+- Professional documentation and deployment infrastructure
+- CLI, API, Docker, and CI/CD support
+
+### [0.1.0] - Initial Release
+- Basic blockchain functionality
+- Core cryptographic features
+- Simple demonstration
+
+---
+
+## Upgrade Guide
+
+### Migrating from 0.1.0 to 1.0.0
+
+The 1.0.0 release introduces breaking changes with a complete reorganization:
+
+#### Import Changes
+
+**Old:**
+```python
+from blockchain import Blockchain, Block, Wallet
+```
+
+**New:**
+```python
+from blockchain_core import Blockchain, Block, Wallet, Transaction
+```
+
+#### File Structure Changes
+
+The monolithic `blockchain.py` has been split into:
+- `blockchain_core/blockchain.py` - Main Blockchain class
+- `blockchain_core/block.py` - Block class
+- `blockchain_core/wallet.py` - Wallet class
+- `blockchain_core/transaction.py` - Transaction class
+- `blockchain_core/utils.py` - Utility functions
+
+#### API Changes
+
+Most APIs remain compatible, but some enhancements:
+- Added type hints to all functions
+- Enhanced error handling
+- Improved logging
+- Better validation
+
+#### New Features
+
+Take advantage of new features:
+- Use the CLI: `blockchain --help`
+- REST API: Start with `python -m api.blockchain_api`
+- Persistence: Save/load blockchain from database
+- Tests: Run with `pytest`
+
+---
+
+## Release Notes Template
+
+### [X.Y.Z] - YYYY-MM-DD
+
+#### Added
+- New features
+
+#### Changed
+- Changes to existing functionality
+
+#### Deprecated
+- Soon-to-be removed features
+
+#### Removed
+- Removed features
+
+#### Fixed
+- Bug fixes
+
+#### Security
+- Security improvements
+
+---
+
+For more details on each release, see the [GitHub Releases](https://github.com/pyenthusiasts/Blockchain/releases) page.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..c4e2411
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,180 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+ community
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Showing patience with beginners and those learning
+* Providing helpful and constructive code reviews
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+ without their explicit permission
+* Conduct which could reasonably be considered inappropriate in a professional
+ setting
+* Dismissing or attacking inclusion-oriented requests
+* Unwelcome comments regarding a person's lifestyle choices and practices
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement through GitHub
+issues or by contacting the project maintainers directly.
+
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+## Additional Guidelines for this Project
+
+### Technical Discussions
+
+* **Be Patient**: Remember that people have varying levels of expertise
+* **Be Constructive**: Focus on improving code and ideas, not attacking people
+* **Be Humble**: Everyone makes mistakes; admit when you're wrong
+* **Be Educational**: Help others learn and grow
+* **Ask Questions**: If something is unclear, ask for clarification
+
+### Code Reviews
+
+* **Be Respectful**: Critique code, not people
+* **Be Specific**: Provide clear, actionable feedback
+* **Be Positive**: Acknowledge good work
+* **Be Helpful**: Suggest improvements rather than just pointing out problems
+* **Be Timely**: Respond to reviews and feedback promptly
+
+### Issue Discussions
+
+* **Be Clear**: Describe issues and suggestions clearly
+* **Be Respectful**: Respect others' time and effort
+* **Be Patient**: Maintainers are often volunteers
+* **Be Collaborative**: Work together to find solutions
+* **Search First**: Check if your issue has already been reported
+
+## Questions?
+
+If you have questions about this Code of Conduct, please open an issue or
+contact the project maintainers.
+
+---
+
+By participating in this project, you agree to abide by this Code of Conduct.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..e041aae
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,339 @@
+# Contributing to Blockchain
+
+Thank you for your interest in contributing to this blockchain implementation! This document provides guidelines and instructions for contributing.
+
+## Table of Contents
+
+- [Code of Conduct](#code-of-conduct)
+- [Getting Started](#getting-started)
+- [How to Contribute](#how-to-contribute)
+- [Development Setup](#development-setup)
+- [Coding Standards](#coding-standards)
+- [Testing Guidelines](#testing-guidelines)
+- [Pull Request Process](#pull-request-process)
+- [Reporting Bugs](#reporting-bugs)
+- [Suggesting Enhancements](#suggesting-enhancements)
+
+## Code of Conduct
+
+This project adheres to a [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
+
+## Getting Started
+
+1. Fork the repository
+2. Clone your fork: `git clone https://github.com/your-username/Blockchain.git`
+3. Add upstream remote: `git remote add upstream https://github.com/pyenthusiasts/Blockchain.git`
+4. Create a feature branch: `git checkout -b feature/your-feature-name`
+
+## How to Contribute
+
+### Types of Contributions
+
+We welcome various types of contributions:
+
+- **Bug fixes**: Fix identified bugs in the codebase
+- **New features**: Implement new blockchain features
+- **Documentation**: Improve or add documentation
+- **Tests**: Add or improve test coverage
+- **Performance improvements**: Optimize existing code
+- **Code quality**: Refactoring and code cleanup
+
+### Development Setup
+
+```bash
+# Clone the repository
+git clone https://github.com/pyenthusiasts/Blockchain.git
+cd Blockchain
+
+# Create a virtual environment
+python -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+
+# Install dependencies
+pip install -r requirements.txt
+pip install -e .
+
+# Install development dependencies
+pip install pytest pytest-cov black flake8 pylint mypy
+```
+
+## Coding Standards
+
+### Python Style Guide
+
+- Follow [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide
+- Use meaningful variable and function names
+- Maximum line length: 120 characters
+- Use type hints for function parameters and return values
+
+### Code Formatting
+
+We use `black` for code formatting:
+
+```bash
+# Format code
+black blockchain_core tests examples
+
+# Check formatting
+black --check blockchain_core tests examples
+```
+
+### Linting
+
+```bash
+# Run flake8
+flake8 blockchain_core tests --max-line-length=120
+
+# Run pylint
+pylint blockchain_core --max-line-length=120
+```
+
+### Type Checking
+
+```bash
+# Run mypy
+mypy blockchain_core --ignore-missing-imports
+```
+
+### Documentation
+
+- Add docstrings to all public functions, classes, and methods
+- Use Google-style docstrings
+- Include type hints in function signatures
+- Update README.md if adding new features
+
+Example docstring:
+
+```python
+def add_transaction(
+ self,
+ sender_public_key: str,
+ recipient_address: str,
+ value: float,
+ signature: bytes
+) -> bool:
+ """
+ Add a new transaction to the pending transactions.
+
+ Args:
+ sender_public_key: Sender's public key
+ recipient_address: Recipient's address
+ value: Transaction amount
+ signature: Transaction signature
+
+ Returns:
+ True if transaction was added, False if invalid
+
+ Raises:
+ ValueError: If transaction data is invalid
+ """
+```
+
+## Testing Guidelines
+
+### Writing Tests
+
+- Write tests for all new features
+- Maintain or improve code coverage
+- Use pytest for testing
+- Place tests in the `tests/` directory
+- Name test files `test_*.py`
+- Name test functions `test_*`
+
+### Running Tests
+
+```bash
+# Run all tests
+pytest
+
+# Run with coverage
+pytest --cov=blockchain_core --cov-report=html
+
+# Run specific test file
+pytest tests/test_blockchain.py
+
+# Run specific test
+pytest tests/test_blockchain.py::TestBlockchain::test_mine_block
+
+# Run verbose
+pytest -v
+
+# Run with markers
+pytest -m "not slow" # Skip slow tests
+```
+
+### Test Structure
+
+```python
+import pytest
+from blockchain_core import Blockchain
+
+class TestBlockchain:
+ """Test cases for Blockchain class."""
+
+ def test_feature_name(self):
+ """Test description."""
+ # Arrange
+ blockchain = Blockchain()
+
+ # Act
+ result = blockchain.some_method()
+
+ # Assert
+ assert result == expected_value
+```
+
+## Pull Request Process
+
+1. **Update your fork**:
+ ```bash
+ git fetch upstream
+ git rebase upstream/main
+ ```
+
+2. **Create a feature branch**:
+ ```bash
+ git checkout -b feature/your-feature-name
+ ```
+
+3. **Make your changes**:
+ - Write clean, documented code
+ - Add tests for new features
+ - Update documentation as needed
+
+4. **Run tests and checks**:
+ ```bash
+ pytest
+ black blockchain_core tests
+ flake8 blockchain_core tests
+ ```
+
+5. **Commit your changes**:
+ ```bash
+ git add .
+ git commit -m "Add feature: description of your changes"
+ ```
+
+ Commit message format:
+ - Use present tense ("Add feature" not "Added feature")
+ - Use imperative mood ("Move cursor to..." not "Moves cursor to...")
+ - Limit first line to 72 characters
+ - Reference issues and pull requests
+
+6. **Push to your fork**:
+ ```bash
+ git push origin feature/your-feature-name
+ ```
+
+7. **Create a Pull Request**:
+ - Go to the original repository on GitHub
+ - Click "New Pull Request"
+ - Select your fork and branch
+ - Fill out the PR template
+ - Link any related issues
+
+### Pull Request Checklist
+
+- [ ] Code follows project style guidelines
+- [ ] Tests pass locally
+- [ ] New tests added for new features
+- [ ] Documentation updated
+- [ ] Commit messages are clear and descriptive
+- [ ] Branch is up to date with main
+- [ ] No merge conflicts
+
+## Reporting Bugs
+
+### Before Submitting a Bug Report
+
+- Check existing issues to avoid duplicates
+- Verify the bug exists in the latest version
+- Collect relevant information
+
+### Bug Report Template
+
+```markdown
+**Describe the bug**
+A clear description of the bug.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Run command '...'
+3. See error
+
+**Expected behavior**
+What you expected to happen.
+
+**Actual behavior**
+What actually happened.
+
+**Environment**
+- OS: [e.g., Ubuntu 20.04]
+- Python version: [e.g., 3.11]
+- Blockchain version: [e.g., 1.0.0]
+
+**Additional context**
+Any other relevant information.
+```
+
+## Suggesting Enhancements
+
+### Before Submitting an Enhancement
+
+- Check if the enhancement already exists
+- Consider if it fits the project scope
+- Think about backward compatibility
+
+### Enhancement Proposal Template
+
+```markdown
+**Is your feature request related to a problem?**
+A clear description of the problem.
+
+**Describe the solution you'd like**
+A clear description of what you want to happen.
+
+**Describe alternatives you've considered**
+Other solutions or features you've considered.
+
+**Additional context**
+Any other relevant information, mockups, or examples.
+```
+
+## Code Review Process
+
+- Maintainers will review your PR
+- Address any requested changes
+- Be patient and respectful
+- PRs may take time to review
+
+### Review Criteria
+
+- Code quality and style
+- Test coverage
+- Documentation
+- Performance impact
+- Security implications
+- Backward compatibility
+
+## Recognition
+
+Contributors will be recognized in:
+- README.md contributors section
+- Release notes
+- GitHub contributors page
+
+## Questions?
+
+- Open an issue with the "question" label
+- Join discussions in issues and pull requests
+- Contact maintainers through GitHub
+
+## License
+
+By contributing, you agree that your contributions will be licensed under the MIT License.
+
+---
+
+Thank you for contributing to this project! Your efforts help make blockchain technology more accessible and educational.
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..cc04226
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,45 @@
+# Dockerfile for Blockchain application
+FROM python:3.11-slim
+
+# Set working directory
+WORKDIR /app
+
+# Set environment variables
+ENV PYTHONUNBUFFERED=1 \
+ PYTHONDONTWRITEBYTECODE=1 \
+ PIP_NO_CACHE_DIR=1 \
+ PIP_DISABLE_PIP_VERSION_CHECK=1
+
+# Install system dependencies
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ gcc \
+ && rm -rf /var/lib/apt/lists/*
+
+# Copy requirements first for better caching
+COPY requirements.txt .
+
+# Install Python dependencies
+RUN pip install --no-cache-dir -r requirements.txt
+
+# Copy the entire project
+COPY . .
+
+# Install the package
+RUN pip install -e .
+
+# Create necessary directories
+RUN mkdir -p /app/data /app/logs /app/wallets
+
+# Set permissions
+RUN chmod +x cli/blockchain_cli.py
+
+# Expose port for future API
+EXPOSE 5000
+
+# Set default command
+CMD ["python", "-m", "examples.basic_usage"]
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
+ CMD python -c "from blockchain_core import Blockchain; bc = Blockchain(); print('healthy' if bc.is_valid_chain() else 'unhealthy')"
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fa368ad
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,177 @@
+.PHONY: help install install-dev test test-cov lint format clean docker-build docker-run docs examples
+
+# Default target
+.DEFAULT_GOAL := help
+
+# Variables
+PYTHON := python3
+PIP := pip3
+PYTEST := pytest
+BLACK := black
+FLAKE8 := flake8
+PYLINT := pylint
+MYPY := mypy
+
+help: ## Show this help message
+ @echo 'Usage: make [target]'
+ @echo ''
+ @echo 'Available targets:'
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'
+
+install: ## Install package and dependencies
+ $(PIP) install -r requirements.txt
+ $(PIP) install -e .
+
+install-dev: ## Install package with development dependencies
+ $(PIP) install -r requirements.txt
+ $(PIP) install -e .
+ $(PIP) install pytest pytest-cov pytest-mock black flake8 pylint mypy bandit safety pre-commit
+
+test: ## Run tests
+ $(PYTEST) tests/ -v
+
+test-cov: ## Run tests with coverage
+ $(PYTEST) tests/ -v --cov=blockchain_core --cov-report=html --cov-report=term --cov-report=xml
+
+test-fast: ## Run tests excluding slow tests
+ $(PYTEST) tests/ -v -m "not slow"
+
+test-watch: ## Run tests in watch mode
+ $(PYTEST) tests/ -v --looponfail
+
+lint: ## Run all linters
+ @echo "Running flake8..."
+ $(FLAKE8) blockchain_core tests examples --max-line-length=120 --exclude=__pycache__,*.pyc
+ @echo "Running pylint..."
+ $(PYLINT) blockchain_core --max-line-length=120 --disable=C0103,R0913 || true
+ @echo "Running mypy..."
+ $(MYPY) blockchain_core --ignore-missing-imports --no-strict-optional || true
+
+format: ## Format code with black
+ $(BLACK) blockchain_core tests examples cli api config
+
+format-check: ## Check code formatting
+ $(BLACK) --check blockchain_core tests examples cli api config
+
+security: ## Run security checks
+ @echo "Running bandit..."
+ bandit -r blockchain_core -f json -o bandit-report.json || true
+ @echo "Running safety..."
+ safety check || true
+
+clean: ## Clean up generated files
+ find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
+ find . -type f -name "*.pyc" -delete
+ find . -type f -name "*.pyo" -delete
+ find . -type f -name "*.orig" -delete
+ find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
+ rm -rf build/ dist/ .pytest_cache/ .coverage htmlcov/ .mypy_cache/
+ rm -f *.db *.blockchain blockchain_export.json bandit-report.json
+ @echo "Cleanup complete!"
+
+clean-all: clean ## Clean everything including venv
+ rm -rf venv/ env/
+
+build: ## Build distribution packages
+ $(PYTHON) setup.py sdist bdist_wheel
+
+docker-build: ## Build Docker image
+ docker build -t blockchain:latest .
+
+docker-run: ## Run Docker container
+ docker run -it --rm blockchain:latest
+
+docker-compose-up: ## Start services with docker-compose
+ docker-compose up
+
+docker-compose-down: ## Stop services with docker-compose
+ docker-compose down
+
+docker-compose-build: ## Build services with docker-compose
+ docker-compose build
+
+docs: ## Generate documentation
+ @echo "Documentation is in docs/ directory"
+ @echo "API docs: docs/API.md"
+ @echo "Contributing: CONTRIBUTING.md"
+ @echo "Changelog: CHANGELOG.md"
+
+examples: ## Run example scripts
+ @echo "Running basic usage example..."
+ $(PYTHON) examples/basic_usage.py
+ @echo "\nRunning advanced features example..."
+ $(PYTHON) examples/advanced_features.py
+
+example-basic: ## Run basic usage example
+ $(PYTHON) examples/basic_usage.py
+
+example-advanced: ## Run advanced features example
+ $(PYTHON) examples/advanced_features.py
+
+cli: ## Show CLI help
+ $(PYTHON) -m cli.blockchain_cli --help
+
+api: ## Run REST API server
+ $(PYTHON) -m api.blockchain_api
+
+api-dev: ## Run REST API server in development mode
+ FLASK_ENV=development $(PYTHON) -m api.blockchain_api
+
+benchmark: ## Run performance benchmarks
+ $(PYTHON) -m tests.benchmarks
+
+pre-commit: ## Install pre-commit hooks
+ pre-commit install
+
+pre-commit-run: ## Run pre-commit on all files
+ pre-commit run --all-files
+
+init: install-dev pre-commit ## Initialize development environment
+ @echo "Development environment initialized!"
+ @echo "Run 'make test' to run tests"
+ @echo "Run 'make examples' to run examples"
+
+check: lint test ## Run linters and tests
+ @echo "All checks passed!"
+
+ci: clean lint test-cov security ## Run CI pipeline locally
+ @echo "CI pipeline complete!"
+
+dev-setup: ## Setup for development
+ @echo "Setting up development environment..."
+ $(PYTHON) -m venv venv
+ @echo "Virtual environment created."
+ @echo "Activate it with: source venv/bin/activate (Linux/Mac) or venv\\Scripts\\activate (Windows)"
+ @echo "Then run: make install-dev"
+
+requirements: ## Update requirements.txt
+ $(PIP) freeze > requirements.txt
+
+upgrade: ## Upgrade all dependencies
+ $(PIP) list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 $(PIP) install -U
+
+version: ## Show version information
+ @echo "Python version:"
+ @$(PYTHON) --version
+ @echo "\nPackage version:"
+ @$(PYTHON) -c "from blockchain_core import __version__; print(__version__)"
+
+stats: ## Show project statistics
+ @echo "=== Project Statistics ==="
+ @echo "\nLines of code:"
+ @find blockchain_core -name "*.py" | xargs wc -l | tail -1
+ @echo "\nTest files:"
+ @find tests -name "test_*.py" | wc -l
+ @echo "\nTotal files:"
+ @find blockchain_core tests examples cli api -name "*.py" | wc -l
+
+todo: ## Show TODO items in code
+ @grep -rn "TODO\|FIXME\|XXX" blockchain_core tests examples cli api || echo "No TODOs found!"
+
+.PHONY: watch
+watch: ## Watch for changes and run tests
+ @echo "Watching for changes..."
+ @while true; do \
+ make test; \
+ inotifywait -qre close_write blockchain_core tests; \
+ done
diff --git a/QUICKSTART.md b/QUICKSTART.md
new file mode 100644
index 0000000..6c079de
--- /dev/null
+++ b/QUICKSTART.md
@@ -0,0 +1,263 @@
+# Quick Start Guide
+
+Get up and running with the blockchain in 5 minutes!
+
+## Installation
+
+```bash
+# Clone the repository
+git clone https://github.com/pyenthusiasts/Blockchain.git
+cd Blockchain
+
+# Install dependencies
+pip install -r requirements.txt
+
+# Install the package
+pip install -e .
+```
+
+## Basic Usage
+
+### 1. Simple Python Script
+
+```python
+from blockchain_core import Blockchain, Wallet
+
+# Create blockchain
+blockchain = Blockchain(difficulty=2, miner_rewards=50)
+
+# Create wallets
+alice = Wallet()
+bob = Wallet()
+
+# Mine a block
+blockchain.mine(alice.address)
+print(f"Alice's balance: {blockchain.get_balance(alice.address)}")
+
+# Create a transaction
+from collections import OrderedDict
+
+transaction = OrderedDict({
+ 'sender_public_key': alice.address,
+ 'recipient_address': bob.address,
+ 'value': 10
+})
+
+signature = alice.sign_transaction(transaction)
+blockchain.add_transaction(alice.address, bob.address, 10, signature)
+
+# Mine to confirm
+blockchain.mine(alice.address)
+
+print(f"Alice's balance: {blockchain.get_balance(alice.address)}")
+print(f"Bob's balance: {blockchain.get_balance(bob.address)}")
+```
+
+### 2. Using the CLI
+
+```bash
+# Create a wallet
+blockchain create-wallet -o mywallet.json
+
+# Mine a block (replace
with your wallet address)
+blockchain mine
+
+# Check balance
+blockchain balance
+
+# View blockchain
+blockchain chain
+
+# Get statistics
+blockchain info
+```
+
+### 3. Using the REST API
+
+```bash
+# Start the API server
+python -m api.blockchain_api
+
+# In another terminal, test the API
+curl http://localhost:5000/
+
+# Create a wallet
+curl -X POST http://localhost:5000/wallet/new
+
+# Get blockchain stats
+curl http://localhost:5000/stats
+```
+
+## Running Examples
+
+```bash
+# Basic usage
+python examples/basic_usage.py
+
+# Advanced features
+python examples/advanced_features.py
+
+# API client
+# (Make sure API server is running first)
+python examples/api_client_example.py
+```
+
+## Using Persistence
+
+```python
+from blockchain_core import (
+ Blockchain,
+ save_blockchain_to_db,
+ load_blockchain_from_db
+)
+
+# Create and populate blockchain
+blockchain = Blockchain()
+# ... add blocks and transactions ...
+
+# Save to database
+save_blockchain_to_db(blockchain, 'my_blockchain.db')
+
+# Load later
+blockchain = load_blockchain_from_db('my_blockchain.db')
+```
+
+## Using Merkle Trees
+
+```python
+from blockchain_core import MerkleTree
+
+# Create tree from transactions
+transactions = [
+ {'sender': 'Alice', 'recipient': 'Bob', 'value': 10},
+ {'sender': 'Bob', 'recipient': 'Charlie', 'value': 20}
+]
+
+tree = MerkleTree(transactions)
+root_hash = tree.get_root_hash()
+
+# Generate and verify proofs
+proof = tree.get_proof(transactions[0])
+is_valid = tree.verify_proof(transactions[0], proof, root_hash)
+print(f"Proof valid: {is_valid}")
+```
+
+## Running Tests
+
+```bash
+# Run all tests
+pytest
+
+# Run with coverage
+pytest --cov=blockchain_core
+
+# Run specific tests
+pytest tests/test_blockchain.py
+
+# Run only fast tests
+pytest -m "not slow"
+```
+
+## Using Make Commands
+
+```bash
+# See all available commands
+make help
+
+# Run tests
+make test
+
+# Run linters
+make lint
+
+# Format code
+make format
+
+# Run benchmarks
+make benchmark
+
+# Build Docker image
+make docker-build
+
+# Full CI pipeline
+make ci
+```
+
+## Docker Usage
+
+```bash
+# Build image
+docker build -t blockchain .
+
+# Run container
+docker run -it blockchain
+
+# Using docker-compose
+docker-compose up
+```
+
+## Development Setup
+
+```bash
+# Initialize development environment
+make init
+
+# Install pre-commit hooks
+pre-commit install
+
+# Run pre-commit checks
+pre-commit run --all-files
+```
+
+## Next Steps
+
+- Read the full [README.md](README.md)
+- Check out [API Documentation](docs/API.md)
+- Review [Contributing Guidelines](CONTRIBUTING.md)
+- Explore [Examples](examples/)
+- Run [Benchmarks](tests/benchmarks.py)
+
+## Troubleshooting
+
+### Import Errors
+
+If you get import errors, make sure you've installed the package:
+```bash
+pip install -e .
+```
+
+### Cryptography Errors
+
+Install/upgrade the cryptography library:
+```bash
+pip install --upgrade cryptography
+```
+
+### Test Failures
+
+Make sure all dependencies are installed:
+```bash
+pip install -r requirements.txt
+```
+
+## Quick Reference
+
+| Task | Command |
+|------|---------|
+| Create wallet | `blockchain create-wallet` |
+| Mine block | `blockchain mine ` |
+| Check balance | `blockchain balance ` |
+| View chain | `blockchain chain` |
+| Run tests | `pytest` |
+| Start API | `python -m api.blockchain_api` |
+| Run example | `python examples/basic_usage.py` |
+| Format code | `make format` |
+| Run benchmarks | `make benchmark` |
+
+## Support
+
+- GitHub Issues: [Report bugs](https://github.com/pyenthusiasts/Blockchain/issues)
+- Documentation: [Full docs](docs/)
+- Examples: [Examples directory](examples/)
+
+Happy blockchain building! ๐
diff --git a/README.md b/README.md
index 655262f..0789c95 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,536 @@
-# Blockchain Application - Simple Demo
+# ๐ Blockchain - A Comprehensive Python Implementation
-A breakdown of this Blockchain structure's main components:
+[](https://www.python.org/downloads/)
+[](https://opensource.org/licenses/MIT)
+[]()
-- Blockchain Class:
+A complete, feature-rich blockchain implementation in Python with cryptographic security, proof-of-work consensus, and a user-friendly CLI interface.
- - Manages the chain of blocks and transactions.
- - Includes methods for registering nodes, adding transactions, mining blocks, validating transactions and proofs, computing balances, etc.
- - Uses SHA-256 hashing for block and transaction integrity.
-
-- Block Class:
+## ๐ Table of Contents
- - Represents each block in the blockchain with an index, list of transactions, timestamp, previous block's hash, nonce, and its own hash.
+- [Features](#-features)
+- [Architecture](#-architecture)
+- [Installation](#-installation)
+- [Quick Start](#-quick-start)
+- [Usage](#-usage)
+ - [Python API](#python-api)
+ - [Command Line Interface](#command-line-interface)
+- [Components](#-components)
+- [Testing](#-testing)
+- [Examples](#-examples)
+- [Configuration](#-configuration)
+- [Contributing](#-contributing)
+- [License](#-license)
-- Wallet Class:
+## โจ Features
- - Handles wallet functionalities such as generating private/public key pairs, serializing public keys, and signing transactions.
+- **๐ Cryptographic Security**: ECDSA key pairs with SECP256K1 curve
+- **โ๏ธ Proof of Work**: Configurable difficulty mining algorithm
+- **๐ฐ Digital Wallets**: Secure wallet management with public/private key pairs
+- **๐ Transaction Signing**: Digital signatures for transaction verification
+- **๐ Chain Validation**: Complete blockchain integrity validation
+- **๐ Network Nodes**: Support for distributed node registration
+- **๐ป CLI Interface**: User-friendly command-line tools
+- **๐งช Comprehensive Tests**: Full test coverage with pytest
+- **๐ Detailed Logging**: Built-in logging for debugging and monitoring
+- **๐ณ Docker Support**: Containerized deployment ready
-- Main Function:
+## ๐๏ธ Architecture
- - Demonstrates the blockchain in action by creating a blockchain instance, wallet instances for a sender and a miner, mining blocks, and performing transactions.
+The blockchain is organized into modular components:
-- Proof of Work (PoW):
+```
+Blockchain/
+โโโ blockchain_core/ # Core blockchain implementation
+โ โโโ blockchain.py # Main blockchain class
+โ โโโ block.py # Block structure and validation
+โ โโโ wallet.py # Wallet and cryptographic functions
+โ โโโ transaction.py # Transaction handling
+โ โโโ utils.py # Utility functions
+โโโ cli/ # Command-line interface
+โโโ config/ # Configuration settings
+โโโ tests/ # Unit and integration tests
+โโโ examples/ # Usage examples
+โโโ docs/ # Documentation
- - Implements PoW for block mining, where miners must find a nonce that, when combined with block data, results in a hash with a specified number of leading zeros (difficulty).
+```
+
+### Main Components
+
+#### Blockchain Class
+
+Manages the chain of blocks and transactions, including:
+- Block creation and validation
+- Transaction pool management
+- Proof of work consensus
+- Balance calculation
+- Chain validation
+
+#### Block Class
+
+Represents each block in the blockchain with:
+- Index and timestamp
+- List of transactions
+- Previous block hash
+- Nonce for proof of work
+- Computed hash
+
+#### Wallet Class
+
+Handles wallet functionalities:
+- Generate private/public key pairs (ECDSA SECP256K1)
+- Serialize and export keys
+- Sign transactions
+- Verify signatures
+
+#### Transaction Class
+
+Manages transaction operations:
+- Transaction creation and validation
+- Digital signature verification
+- Structured transaction data
+
+## ๐ฆ Installation
+
+### Prerequisites
+
+- Python 3.8 or higher
+- pip package manager
+
+### Standard Installation
+
+```bash
+# Clone the repository
+git clone https://github.com/pyenthusiasts/Blockchain.git
+cd Blockchain
+
+# Install dependencies
+pip install -r requirements.txt
+
+# Install the package
+pip install -e .
+```
+
+### Docker Installation
+
+```bash
+# Build the Docker image
+docker build -t blockchain .
+
+# Run the container
+docker run -it blockchain
+```
+
+## ๐ Quick Start
+
+### Basic Example
+
+```python
+from blockchain_core import Blockchain, Wallet
+
+# Create a blockchain
+blockchain = Blockchain(difficulty=2, miner_rewards=50)
+
+# Create wallets
+alice = Wallet()
+bob = Wallet()
+
+# Mine a block
+blockchain.mine(alice.address)
+
+# Create a transaction
+from collections import OrderedDict
+
+transaction = OrderedDict({
+ 'sender_public_key': alice.address,
+ 'recipient_address': bob.address,
+ 'value': 10
+})
+
+signature = alice.sign_transaction(transaction)
+blockchain.add_transaction(alice.address, bob.address, 10, signature)
+
+# Mine to confirm
+blockchain.mine(alice.address)
+
+# Check balances
+print(f"Alice's balance: {blockchain.get_balance(alice.address)}")
+print(f"Bob's balance: {blockchain.get_balance(bob.address)}")
+```
+
+## ๐ก Usage
+
+### Python API
+
+#### Creating a Blockchain
+
+```python
+from blockchain_core import Blockchain
+
+# Create with default settings
+blockchain = Blockchain()
+
+# Create with custom settings
+blockchain = Blockchain(difficulty=4, miner_rewards=25)
+```
+
+#### Creating and Managing Wallets
+
+```python
+from blockchain_core import Wallet
+
+# Create a new wallet
+wallet = Wallet()
+
+# Export private key
+private_key = wallet.export_private_key()
+
+# Import wallet from private key
+imported_wallet = Wallet.from_private_key(private_key)
+
+# Sign a transaction
+signature = wallet.sign_transaction(transaction_data)
+```
+
+#### Creating Transactions
+
+```python
+from collections import OrderedDict
+
+# Create transaction data
+transaction = OrderedDict({
+ 'sender_public_key': sender_wallet.address,
+ 'recipient_address': recipient_wallet.address,
+ 'value': 50
+})
+
+# Sign the transaction
+signature = sender_wallet.sign_transaction(transaction)
+
+# Add to blockchain
+blockchain.add_transaction(
+ sender_wallet.address,
+ recipient_wallet.address,
+ 50,
+ signature
+)
+```
+
+#### Mining Blocks
+
+```python
+# Mine a new block
+block_index = blockchain.mine(miner_wallet.address)
+
+if block_index:
+ print(f"Block {block_index} mined successfully!")
+```
+
+#### Checking Balances
+
+```python
+balance = blockchain.get_balance(wallet.address)
+print(f"Balance: {balance}")
+```
+
+#### Validating the Chain
+
+```python
+if blockchain.is_valid_chain():
+ print("Blockchain is valid!")
+else:
+ print("Blockchain has been compromised!")
+```
+
+### Command Line Interface
+
+The blockchain includes a comprehensive CLI for all operations.
+
+#### Create a Wallet
+
+```bash
+# Create and display wallet
+blockchain create-wallet
+
+# Save wallet to file
+blockchain create-wallet -o mywallet.json
+```
+
+#### Check Balance
+
+```bash
+blockchain balance
+```
+
+#### Mine Blocks
+
+```bash
+# Mine with default difficulty
+blockchain mine
+
+# Mine with custom difficulty
+blockchain mine -d 4
+```
+
+#### Send Transactions
+
+```bash
+blockchain send
+```
+
+#### View Blockchain
+
+```bash
+# View summary
+blockchain chain
+
+# View detailed information
+blockchain chain --detail
+```
+
+#### View Pending Transactions
+
+```bash
+blockchain pending
+```
+
+#### Validate Blockchain
+
+```bash
+blockchain validate
+```
+
+#### Export Blockchain
+
+```bash
+blockchain export blockchain_data.json
+```
+
+#### Show Statistics
+
+```bash
+blockchain info
+```
+
+## ๐งฉ Components
+
+### Blockchain (`blockchain_core/blockchain.py`)
+
+Main blockchain implementation with:
+- Genesis block creation
+- Transaction management
+- Proof of work algorithm
+- Block addition and validation
+- Balance calculation
+- Network node management
+
+### Block (`blockchain_core/block.py`)
+
+Block structure with:
+- Index, timestamp, transactions
+- Previous hash linkage
+- Nonce for mining
+- Hash computation
+- Validation methods
+
+### Wallet (`blockchain_core/wallet.py`)
+
+Cryptographic wallet with:
+- ECDSA key generation (SECP256K1)
+- Key serialization and export
+- Transaction signing
+- Signature verification
+
+### Transaction (`blockchain_core/transaction.py`)
+
+Transaction handling with:
+- Structured transaction format
+- Digital signatures
+- Validation methods
+- Coinbase transactions
+
+### Utils (`blockchain_core/utils.py`)
+
+Utility functions:
+- Hash computation
+- Address validation
+- Transaction serialization
+- Logging setup
+
+## ๐งช Testing
+
+The project includes comprehensive unit tests with pytest.
+
+```bash
+# Run all tests
+pytest
+
+# Run with coverage
+pytest --cov=blockchain_core
+
+# Run specific test file
+pytest tests/test_blockchain.py
+
+# Run with verbose output
+pytest -v
+```
+
+### Test Coverage
+
+- โ
Block creation and validation
+- โ
Wallet generation and signing
+- โ
Transaction creation and validation
+- โ
Blockchain operations
+- โ
Proof of work
+- โ
Chain validation
+- โ
Balance calculations
+- โ
Utility functions
+
+## ๐ Examples
+
+### Basic Usage
+
+See `examples/basic_usage.py` for a complete basic example covering:
+- Blockchain creation
+- Wallet management
+- Mining
+- Transactions
+- Balance checking
+
+Run it:
+```bash
+python examples/basic_usage.py
+```
+
+### Advanced Features
+
+See `examples/advanced_features.py` for advanced usage:
+- Multiple transactions
+- Wallet import/export
+- Transaction validation
+- Failed transaction handling
+- Chain exploration
+- Blockchain export
+
+Run it:
+```bash
+python examples/advanced_features.py
+```
+
+## โ๏ธ Configuration
+
+Configuration is managed in `config/config.py`:
+
+```python
+# Mining settings
+DIFFICULTY = 2 # Number of leading zeros required
+MINER_REWARD = 50 # Reward for mining a block
+INITIAL_BALANCE = 150 # Initial wallet balance
+
+# Cryptography
+CURVE = 'SECP256K1' # Elliptic curve for ECDSA
+HASH_ALGORITHM = 'SHA256' # Hash algorithm
+
+# Network
+DEFAULT_PORT = 5000 # Default network port
+MAX_NODES = 100 # Maximum network nodes
+
+# Logging
+LOG_LEVEL = 'INFO' # Logging level
+```
+
+## ๐ณ Docker Support
+
+### Build and Run
+
+```bash
+# Build image
+docker build -t blockchain .
+
+# Run container
+docker run -it blockchain
+
+# Run with volume mount
+docker run -it -v $(pwd)/data:/app/data blockchain
+```
+
+### Docker Compose
+
+```bash
+# Start services
+docker-compose up
+
+# Stop services
+docker-compose down
+```
+
+## ๐ API Documentation
+
+For detailed API documentation, see `docs/API.md`.
+
+## ๐ Security Considerations
+
+- **Private Keys**: Always keep private keys secure and never share them
+- **Initial Balance**: The default initial balance is for demonstration purposes
+- **Network Security**: In production, implement proper network security
+- **Consensus**: The proof-of-work difficulty should be adjusted based on network needs
+
+## ๐ฃ๏ธ Roadmap
+
+- [ ] REST API implementation
+- [ ] Consensus algorithm improvements (PoS)
+- [ ] Smart contract support
+- [ ] Web interface
+- [ ] Merkle tree implementation
+- [ ] Enhanced networking capabilities
+- [ ] Database persistence
+
+## ๐ค Contributing
+
+Contributions are welcome! Please follow these steps:
+
+1. Fork the repository
+2. Create a feature branch (`git checkout -b feature/amazing-feature`)
+3. Commit your changes (`git commit -m 'Add amazing feature'`)
+4. Push to the branch (`git push origin feature/amazing-feature`)
+5. Open a Pull Request
+
+### Development Setup
+
+```bash
+# Install development dependencies
+pip install -r requirements.txt
+
+# Run tests
+pytest
+
+# Run linting
+flake8 blockchain_core tests
+
+# Format code
+black blockchain_core tests
+```
+
+## ๐ License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
+
+## ๐ฅ Authors
+
+**Python Enthusiasts** - [GitHub](https://github.com/pyenthusiasts)
+
+## ๐ Acknowledgments
+
+- Inspired by Bitcoin and Ethereum implementations
+- Built with Python's cryptography library
+- Thanks to all contributors
+
+## ๐ฎ Contact
+
+For questions, issues, or suggestions:
+- Open an issue on GitHub
+- Email: [Contact through GitHub]
+
+---
+
+**โญ If you find this project useful, please consider giving it a star!**
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..6b1a5bd
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,305 @@
+# Security Policy
+
+## Supported Versions
+
+We take security seriously and actively maintain the following versions:
+
+| Version | Supported |
+| ------- | ------------------ |
+| 1.0.x | :white_check_mark: |
+| < 1.0 | :x: |
+
+## Reporting a Vulnerability
+
+We appreciate security researchers and users who report vulnerabilities to us. We take all security reports seriously.
+
+### How to Report
+
+**Please do NOT report security vulnerabilities through public GitHub issues.**
+
+Instead, please report security vulnerabilities by:
+
+1. **Email**: Send details to the repository maintainers through GitHub (use the "Security" tab if available)
+2. **Private Issue**: If email is not available, create a private security advisory on GitHub
+
+### What to Include
+
+When reporting a vulnerability, please include:
+
+- **Description**: Clear description of the vulnerability
+- **Impact**: Potential impact and severity
+- **Steps to Reproduce**: Detailed steps to reproduce the issue
+- **Proof of Concept**: If possible, include PoC code
+- **Suggested Fix**: If you have ideas on how to fix it
+- **Disclosure Timeline**: Your expected disclosure timeline
+
+### Example Report
+
+```markdown
+**Vulnerability Type**: [e.g., Authentication Bypass, Code Injection]
+
+**Affected Component**: [e.g., wallet.py, transaction validation]
+
+**Description**:
+Detailed description of the vulnerability...
+
+**Impact**:
+What an attacker could do with this vulnerability...
+
+**Steps to Reproduce**:
+1. Step one
+2. Step two
+3. See vulnerability
+
+**Proof of Concept**:
+```python
+# PoC code here
+```
+
+**Suggested Fix**:
+Recommendations for fixing the issue...
+```
+
+## Response Timeline
+
+- **Initial Response**: Within 48 hours
+- **Confirmation**: Within 7 days
+- **Fix Development**: Depends on severity
+ - Critical: 1-7 days
+ - High: 7-14 days
+ - Medium: 14-30 days
+ - Low: 30-90 days
+- **Public Disclosure**: After fix is released
+
+## Security Best Practices
+
+### For Users
+
+#### Private Key Security
+
+1. **Never share private keys**
+ ```python
+ # DON'T do this
+ print(wallet.export_private_key()) # Logs private key
+ ```
+
+2. **Store private keys securely**
+ - Use encryption for stored keys
+ - Use secure key management systems in production
+ - Never commit keys to version control
+
+3. **Use environment variables**
+ ```python
+ import os
+ private_key = os.getenv('WALLET_PRIVATE_KEY')
+ ```
+
+#### Network Security
+
+1. **Use HTTPS in production**
+ ```python
+ # Production
+ blockchain.register_node('https://node1.example.com')
+
+ # Not for production
+ blockchain.register_node('http://node1.example.com')
+ ```
+
+2. **Validate node addresses**
+3. **Implement rate limiting on API endpoints**
+
+#### Input Validation
+
+1. **Validate all inputs**
+ ```python
+ def validate_address(address: str) -> bool:
+ if not address or not isinstance(address, str):
+ return False
+ return address.startswith('-----BEGIN PUBLIC KEY-----')
+ ```
+
+2. **Sanitize user inputs**
+3. **Use parameterized queries for database operations**
+
+#### Transaction Security
+
+1. **Always verify signatures**
+ ```python
+ if not blockchain.verify_transaction_signature(
+ sender_key, signature, transaction
+ ):
+ raise ValueError("Invalid signature")
+ ```
+
+2. **Check balances before transactions**
+3. **Validate transaction amounts**
+
+### For Developers
+
+#### Code Security
+
+1. **Follow secure coding practices**
+2. **Use static analysis tools**
+ ```bash
+ bandit -r blockchain_core
+ safety check
+ ```
+
+3. **Keep dependencies updated**
+ ```bash
+ pip list --outdated
+ pip install --upgrade cryptography
+ ```
+
+#### Cryptography
+
+1. **Use established cryptographic libraries**
+ - We use `cryptography` library
+ - Don't implement custom crypto
+
+2. **Use appropriate key sizes**
+ - SECP256K1 for ECDSA
+ - SHA-256 for hashing
+
+3. **Secure random number generation**
+ ```python
+ from cryptography.hazmat.primitives.asymmetric import ec
+ private_key = ec.generate_private_key(ec.SECP256K1())
+ ```
+
+#### API Security
+
+1. **Implement authentication**
+2. **Use CORS appropriately**
+3. **Rate limiting**
+4. **Input validation**
+5. **Error handling** (don't leak sensitive info)
+
+#### Database Security
+
+1. **Use parameterized queries**
+ ```python
+ cursor.execute(
+ 'SELECT * FROM blocks WHERE block_index = ?',
+ (index,)
+ )
+ ```
+
+2. **Encrypt sensitive data**
+3. **Secure database files**
+
+## Known Security Considerations
+
+### Educational Purpose
+
+**This implementation is primarily for educational purposes.** For production use:
+
+1. **Initial Balance**: The default initial balance (150) is for demonstration only
+2. **Proof of Work**: Adjust difficulty for production networks
+3. **Network Security**: Implement proper node authentication
+4. **Consensus**: Consider more advanced consensus mechanisms
+5. **51% Attack**: Be aware of blockchain security limitations
+
+### Cryptographic Notes
+
+1. **Key Management**: Implement proper key management systems
+2. **Signature Verification**: Always verify transaction signatures
+3. **Hash Functions**: SHA-256 is used throughout
+4. **Random Number Generation**: Uses system-secure random
+
+### API Security
+
+The REST API should be secured with:
+- Authentication (JWT, API keys)
+- HTTPS in production
+- Rate limiting
+- Input validation
+- CORS configuration
+
+## Security Features
+
+### Implemented
+
+- โ
ECDSA signature verification
+- โ
Transaction validation
+- โ
Balance checking
+- โ
Chain validation
+- โ
Input sanitization in CLI
+- โ
Type hints for better code safety
+- โ
Error handling throughout
+- โ
Logging for audit trails
+
+### Planned
+
+- โณ JWT authentication for API
+- โณ Enhanced encryption for stored keys
+- โณ Rate limiting middleware
+- โณ Advanced consensus mechanisms
+- โณ Multi-signature support
+
+## Security Testing
+
+### Running Security Checks
+
+```bash
+# Bandit security linter
+bandit -r blockchain_core
+
+# Safety - check dependencies
+safety check
+
+# Check for secrets in code
+git secrets --scan
+
+# Run security tests
+pytest tests/ -m security
+```
+
+### Security Test Coverage
+
+- Transaction signature validation
+- Balance validation
+- Input validation
+- SQL injection prevention
+- Chain validation
+
+## Compliance
+
+This project aims to follow:
+- OWASP Top 10 guidelines
+- CWE (Common Weakness Enumeration) standards
+- Secure coding best practices
+
+## Dependencies
+
+We regularly monitor and update dependencies for security vulnerabilities:
+
+```bash
+# Check for vulnerabilities
+pip-audit
+
+# Update dependencies
+pip install --upgrade -r requirements.txt
+```
+
+## Disclosure Policy
+
+- We follow responsible disclosure practices
+- Security vulnerabilities will be disclosed after fixes are available
+- Credit will be given to security researchers who report vulnerabilities
+
+## Hall of Fame
+
+We thank the following security researchers (list will be updated):
+
+*No vulnerabilities reported yet*
+
+## Contact
+
+For security concerns, please contact the maintainers through:
+- GitHub Security Advisories
+- Repository maintainers' GitHub profiles
+
+---
+
+**Remember**: Security is everyone's responsibility. If you see something, say something.
diff --git a/api/__init__.py b/api/__init__.py
new file mode 100644
index 0000000..340beda
--- /dev/null
+++ b/api/__init__.py
@@ -0,0 +1,7 @@
+"""
+REST API module for blockchain operations.
+"""
+
+from .blockchain_api import app, run_server
+
+__all__ = ['app', 'run_server']
diff --git a/api/blockchain_api.py b/api/blockchain_api.py
new file mode 100644
index 0000000..876869d
--- /dev/null
+++ b/api/blockchain_api.py
@@ -0,0 +1,267 @@
+"""
+REST API for the blockchain application.
+"""
+
+from flask import Flask, jsonify, request
+from flask_cors import CORS
+import logging
+from typing import Dict, Any
+from collections import OrderedDict
+
+from blockchain_core import Blockchain, Wallet
+from config import DIFFICULTY, MINER_REWARD
+
+# Initialize Flask app
+app = Flask(__name__)
+CORS(app) # Enable CORS for all routes
+
+# Configure logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+# Global blockchain instance
+blockchain = Blockchain(difficulty=DIFFICULTY, miner_rewards=MINER_REWARD)
+
+# Store node identifier
+from uuid import uuid4
+node_identifier = str(uuid4()).replace('-', '')
+
+
+@app.route('/', methods=['GET'])
+def index():
+ """API root endpoint."""
+ return jsonify({
+ 'name': 'Blockchain API',
+ 'version': '1.0.0',
+ 'endpoints': {
+ 'GET /': 'API information',
+ 'GET /chain': 'Get the full blockchain',
+ 'GET /chain/validate': 'Validate the blockchain',
+ 'GET /chain/length': 'Get blockchain length',
+ 'POST /mine': 'Mine a new block',
+ 'GET /transactions/pending': 'Get pending transactions',
+ 'POST /transactions/new': 'Create a new transaction',
+ 'GET /balance/': 'Get balance for an address',
+ 'POST /nodes/register': 'Register a new node',
+ 'GET /nodes': 'Get registered nodes',
+ 'POST /wallet/new': 'Create a new wallet',
+ 'GET /stats': 'Get blockchain statistics'
+ }
+ }), 200
+
+
+@app.route('/chain', methods=['GET'])
+def get_chain():
+ """Get the full blockchain."""
+ response = blockchain.to_dict()
+ return jsonify(response), 200
+
+
+@app.route('/chain/validate', methods=['GET'])
+def validate_chain():
+ """Validate the blockchain."""
+ is_valid = blockchain.is_valid_chain()
+ return jsonify({
+ 'valid': is_valid,
+ 'message': 'Blockchain is valid' if is_valid else 'Blockchain is invalid'
+ }), 200
+
+
+@app.route('/chain/length', methods=['GET'])
+def chain_length():
+ """Get the length of the blockchain."""
+ return jsonify({
+ 'length': blockchain.get_chain_length()
+ }), 200
+
+
+@app.route('/mine', methods=['POST'])
+def mine():
+ """Mine a new block."""
+ data = request.get_json()
+
+ if not data or 'miner_address' not in data:
+ return jsonify({
+ 'error': 'Missing miner_address in request'
+ }), 400
+
+ miner_address = data['miner_address']
+
+ logger.info(f"Mining new block for {miner_address[:20]}...")
+ block_index = blockchain.mine(miner_address)
+
+ if block_index:
+ return jsonify({
+ 'message': 'Block mined successfully',
+ 'block_index': block_index,
+ 'block': blockchain.chain[block_index].to_dict()
+ }), 201
+ else:
+ return jsonify({
+ 'error': 'Mining failed'
+ }), 500
+
+
+@app.route('/transactions/pending', methods=['GET'])
+def get_pending_transactions():
+ """Get all pending transactions."""
+ return jsonify({
+ 'transactions': blockchain.transactions,
+ 'count': len(blockchain.transactions)
+ }), 200
+
+
+@app.route('/transactions/new', methods=['POST'])
+def new_transaction():
+ """Create a new transaction."""
+ data = request.get_json()
+
+ required_fields = ['sender_public_key', 'recipient_address', 'value', 'signature']
+ if not all(field in data for field in required_fields):
+ return jsonify({
+ 'error': f'Missing required fields. Required: {required_fields}'
+ }), 400
+
+ # Convert signature from hex string to bytes if needed
+ signature = data['signature']
+ if isinstance(signature, str):
+ signature = bytes.fromhex(signature)
+
+ success = blockchain.add_transaction(
+ data['sender_public_key'],
+ data['recipient_address'],
+ data['value'],
+ signature
+ )
+
+ if success:
+ return jsonify({
+ 'message': 'Transaction added successfully',
+ 'transaction': {
+ 'sender': data['sender_public_key'][:20] + '...',
+ 'recipient': data['recipient_address'][:20] + '...',
+ 'value': data['value']
+ }
+ }), 201
+ else:
+ return jsonify({
+ 'error': 'Transaction validation failed'
+ }), 400
+
+
+@app.route('/balance/', methods=['GET'])
+def get_balance(address):
+ """Get the balance for an address."""
+ balance = blockchain.get_balance(address)
+ return jsonify({
+ 'address': address[:20] + '...' if len(address) > 20 else address,
+ 'balance': balance
+ }), 200
+
+
+@app.route('/nodes/register', methods=['POST'])
+def register_nodes():
+ """Register new network nodes."""
+ data = request.get_json()
+
+ if not data or 'nodes' not in data:
+ return jsonify({
+ 'error': 'Missing nodes list in request'
+ }), 400
+
+ nodes = data['nodes']
+ if not isinstance(nodes, list):
+ return jsonify({
+ 'error': 'nodes must be a list'
+ }), 400
+
+ added = []
+ for node in nodes:
+ if blockchain.register_node(node):
+ added.append(node)
+
+ return jsonify({
+ 'message': f'{len(added)} node(s) registered',
+ 'total_nodes': len(blockchain.nodes),
+ 'nodes': list(blockchain.nodes)
+ }), 201
+
+
+@app.route('/nodes', methods=['GET'])
+def get_nodes():
+ """Get all registered nodes."""
+ return jsonify({
+ 'nodes': list(blockchain.nodes),
+ 'count': len(blockchain.nodes)
+ }), 200
+
+
+@app.route('/wallet/new', methods=['POST'])
+def create_wallet():
+ """Create a new wallet."""
+ wallet = Wallet()
+
+ return jsonify({
+ 'message': 'Wallet created successfully',
+ 'address': wallet.address,
+ 'private_key': wallet.export_private_key(),
+ 'warning': 'Keep your private key secure and never share it!'
+ }), 201
+
+
+@app.route('/stats', methods=['GET'])
+def get_stats():
+ """Get blockchain statistics."""
+ total_transactions = sum(len(block.transactions) for block in blockchain.chain)
+
+ return jsonify({
+ 'blocks': blockchain.get_chain_length(),
+ 'total_transactions': total_transactions,
+ 'pending_transactions': len(blockchain.transactions),
+ 'difficulty': blockchain.difficulty,
+ 'miner_reward': blockchain.miner_rewards,
+ 'network_nodes': len(blockchain.nodes),
+ 'valid': blockchain.is_valid_chain(),
+ 'node_identifier': node_identifier
+ }), 200
+
+
+@app.route('/block/', methods=['GET'])
+def get_block(index):
+ """Get a specific block by index."""
+ if index < 0 or index >= len(blockchain.chain):
+ return jsonify({
+ 'error': f'Block index {index} not found'
+ }), 404
+
+ block = blockchain.chain[index]
+ return jsonify(block.to_dict()), 200
+
+
+@app.errorhandler(404)
+def not_found(error):
+ """Handle 404 errors."""
+ return jsonify({
+ 'error': 'Endpoint not found'
+ }), 404
+
+
+@app.errorhandler(500)
+def internal_error(error):
+ """Handle 500 errors."""
+ logger.error(f"Internal error: {error}")
+ return jsonify({
+ 'error': 'Internal server error'
+ }), 500
+
+
+def run_server(host='0.0.0.0', port=5000, debug=False):
+ """Run the Flask server."""
+ logger.info(f"Starting Blockchain API server on {host}:{port}")
+ app.run(host=host, port=port, debug=debug)
+
+
+if __name__ == '__main__':
+ import sys
+ port = int(sys.argv[1]) if len(sys.argv) > 1 else 5000
+ run_server(port=port, debug=True)
diff --git a/blockchain.py b/blockchain.py.old
similarity index 100%
rename from blockchain.py
rename to blockchain.py.old
diff --git a/blockchain_core/__init__.py b/blockchain_core/__init__.py
new file mode 100644
index 0000000..5ad47ec
--- /dev/null
+++ b/blockchain_core/__init__.py
@@ -0,0 +1,38 @@
+"""
+Blockchain Core - A simple but comprehensive blockchain implementation.
+
+This package provides all the core functionality for a blockchain system including:
+- Block creation and validation
+- Transaction management and signing
+- Wallet management with cryptographic keys
+- Proof of work consensus algorithm
+- Network node management
+- Merkle tree for efficient transaction verification
+- Database persistence layer
+"""
+
+from .blockchain import Blockchain
+from .block import Block
+from .wallet import Wallet
+from .transaction import Transaction
+from .utils import setup_logging, compute_hash, validate_address
+from .merkle_tree import MerkleTree, MerkleNode
+from .persistence import BlockchainDB, save_blockchain_to_db, load_blockchain_from_db
+
+__version__ = '2.0.0'
+__author__ = 'Python Enthusiasts'
+
+__all__ = [
+ 'Blockchain',
+ 'Block',
+ 'Wallet',
+ 'Transaction',
+ 'MerkleTree',
+ 'MerkleNode',
+ 'BlockchainDB',
+ 'save_blockchain_to_db',
+ 'load_blockchain_from_db',
+ 'setup_logging',
+ 'compute_hash',
+ 'validate_address',
+]
diff --git a/blockchain_core/block.py b/blockchain_core/block.py
new file mode 100644
index 0000000..1c11562
--- /dev/null
+++ b/blockchain_core/block.py
@@ -0,0 +1,118 @@
+"""
+Block class for the blockchain.
+"""
+
+import json
+import hashlib
+from time import time
+from typing import List, Dict, Any, Optional
+
+
+class Block:
+ """
+ Represents a single block in the blockchain.
+
+ Attributes:
+ index: Position of the block in the chain
+ transactions: List of transactions included in the block
+ timestamp: Time when the block was created
+ previous_hash: Hash of the previous block
+ nonce: Number used once for proof of work
+ hash: Hash of the current block
+ """
+
+ def __init__(
+ self,
+ index: int,
+ transactions: List[Dict[str, Any]],
+ timestamp: float,
+ previous_hash: str,
+ nonce: int = 0
+ ):
+ """
+ Initialize a new Block.
+
+ Args:
+ index: Block position in the chain
+ transactions: List of transaction dictionaries
+ timestamp: Block creation timestamp
+ previous_hash: Hash of the previous block
+ nonce: Proof of work nonce (default: 0)
+ """
+ self.index = index
+ self.transactions = transactions
+ self.timestamp = timestamp
+ self.previous_hash = previous_hash
+ self.nonce = nonce
+ self.hash = self.compute_hash()
+
+ def compute_hash(self) -> str:
+ """
+ Compute SHA-256 hash of the block.
+
+ Returns:
+ Hexadecimal hash string
+ """
+ block_string = json.dumps(self.__dict__, sort_keys=True)
+ return hashlib.sha256(block_string.encode()).hexdigest()
+
+ def to_dict(self) -> Dict[str, Any]:
+ """
+ Convert block to dictionary representation.
+
+ Returns:
+ Dictionary containing all block data
+ """
+ return {
+ 'index': self.index,
+ 'transactions': self.transactions,
+ 'timestamp': self.timestamp,
+ 'previous_hash': self.previous_hash,
+ 'nonce': self.nonce,
+ 'hash': self.hash
+ }
+
+ def __repr__(self) -> str:
+ """
+ String representation of the block.
+
+ Returns:
+ Formatted block information
+ """
+ return (
+ f"Block(index={self.index}, "
+ f"transactions={len(self.transactions)}, "
+ f"timestamp={self.timestamp}, "
+ f"hash={self.hash[:16]}...)"
+ )
+
+ @classmethod
+ def from_dict(cls, data: Dict[str, Any]) -> 'Block':
+ """
+ Create a Block instance from a dictionary.
+
+ Args:
+ data: Dictionary containing block data
+
+ Returns:
+ New Block instance
+ """
+ block = cls(
+ index=data['index'],
+ transactions=data['transactions'],
+ timestamp=data['timestamp'],
+ previous_hash=data['previous_hash'],
+ nonce=data.get('nonce', 0)
+ )
+ if 'hash' in data:
+ block.hash = data['hash']
+ return block
+
+ def is_valid(self) -> bool:
+ """
+ Check if block hash is valid.
+
+ Returns:
+ True if hash matches computed hash, False otherwise
+ """
+ return self.hash == self.compute_hash()
diff --git a/blockchain_core/blockchain.py b/blockchain_core/blockchain.py
new file mode 100644
index 0000000..cb4d45b
--- /dev/null
+++ b/blockchain_core/blockchain.py
@@ -0,0 +1,349 @@
+"""
+Main Blockchain class implementation.
+"""
+
+import hashlib
+import json
+from time import time
+from typing import List, Dict, Any, Optional, Set
+from .block import Block
+from .transaction import Transaction
+from .wallet import Wallet
+from .utils import logger
+
+
+class Blockchain:
+ """
+ Main blockchain implementation with proof of work consensus.
+
+ Attributes:
+ transactions: List of pending transactions
+ chain: List of blocks in the blockchain
+ nodes: Set of network nodes
+ difficulty: Proof of work difficulty level
+ miner_rewards: Reward amount for mining a block
+ """
+
+ def __init__(self, difficulty: int = 2, miner_rewards: float = 50):
+ """
+ Initialize a new Blockchain.
+
+ Args:
+ difficulty: Number of leading zeros required in block hash
+ miner_rewards: Reward amount for successfully mining a block
+ """
+ self.transactions: List[Dict[str, Any]] = []
+ self.chain: List[Block] = []
+ self.nodes: Set[str] = set()
+ self.difficulty = difficulty
+ self.miner_rewards = miner_rewards
+ self.create_genesis_block()
+ logger.info("Blockchain initialized with difficulty %d", difficulty)
+
+ def create_genesis_block(self) -> None:
+ """
+ Create the genesis (first) block of the blockchain.
+ """
+ genesis_block = Block(0, [], time(), "0")
+ genesis_block.hash = genesis_block.compute_hash()
+ self.chain.append(genesis_block)
+ logger.info("Genesis block created: %s", genesis_block.hash)
+
+ def register_node(self, address: str) -> bool:
+ """
+ Register a new node in the network.
+
+ Args:
+ address: Network address of the node
+
+ Returns:
+ True if node was added, False if already registered
+ """
+ if address in self.nodes:
+ return False
+ self.nodes.add(address)
+ logger.info("Node registered: %s", address)
+ return True
+
+ def verify_transaction_signature(
+ self,
+ sender_public_key: str,
+ signature: bytes,
+ transaction: Dict[str, Any]
+ ) -> bool:
+ """
+ Verify a transaction signature.
+
+ Args:
+ sender_public_key: Sender's public key
+ signature: Transaction signature
+ transaction: Transaction data
+
+ Returns:
+ True if signature is valid, False otherwise
+ """
+ return Wallet.verify_signature(sender_public_key, signature, transaction)
+
+ def add_transaction(
+ self,
+ sender_public_key: str,
+ recipient_address: str,
+ value: float,
+ signature: bytes
+ ) -> bool:
+ """
+ Add a new transaction to the pending transactions.
+
+ Args:
+ sender_public_key: Sender's public key
+ recipient_address: Recipient's address
+ value: Transaction amount
+ signature: Transaction signature
+
+ Returns:
+ True if transaction was added, False if invalid
+ """
+ from collections import OrderedDict
+
+ transaction = OrderedDict({
+ 'sender_public_key': sender_public_key,
+ 'recipient_address': recipient_address,
+ 'value': value
+ })
+
+ # Verify signature
+ if not self.verify_transaction_signature(sender_public_key, signature, transaction):
+ logger.warning("Transaction rejected: Invalid signature")
+ return False
+
+ # Check sender balance
+ sender_balance = self.get_balance(sender_public_key)
+ if sender_balance < value:
+ logger.warning("Transaction rejected: Insufficient balance (has: %f, needs: %f)",
+ sender_balance, value)
+ return False
+
+ self.transactions.append(transaction)
+ logger.info("Transaction added: %s -> %s (%.2f)",
+ sender_public_key[:20], recipient_address[:20], value)
+ return True
+
+ def last_block(self) -> Block:
+ """
+ Get the last block in the chain.
+
+ Returns:
+ The most recent block
+ """
+ return self.chain[-1]
+
+ def add_block(self, block: Block, proof: str, miner_address: str) -> bool:
+ """
+ Add a new block to the blockchain.
+
+ Args:
+ block: Block to add
+ proof: Proof of work hash
+ miner_address: Address of the miner
+
+ Returns:
+ True if block was added, False if invalid
+ """
+ previous_hash = self.last_block().hash
+
+ # Verify previous hash
+ if previous_hash != block.previous_hash:
+ logger.error("Block rejected: Invalid previous hash")
+ return False
+
+ # Verify proof of work
+ if not self.valid_proof(block.transactions, block.previous_hash, proof, self.difficulty):
+ logger.error("Block rejected: Invalid proof of work")
+ return False
+
+ block.hash = proof
+ self.chain.append(block)
+ self.transactions = []
+
+ # Add mining reward transaction for next block
+ self.transactions.append({
+ 'sender_public_key': 'network',
+ 'recipient_address': miner_address,
+ 'value': self.miner_rewards
+ })
+
+ logger.info("Block added: index=%d, hash=%s", block.index, block.hash[:16])
+ return True
+
+ @staticmethod
+ def valid_proof(
+ transactions: List[Dict[str, Any]],
+ last_hash: str,
+ proof: str,
+ difficulty: int
+ ) -> bool:
+ """
+ Validate a proof of work.
+
+ Args:
+ transactions: List of transactions in the block
+ last_hash: Hash of the previous block
+ proof: Proof of work to validate
+ difficulty: Required difficulty level
+
+ Returns:
+ True if proof is valid, False otherwise
+ """
+ transactions_serialized = json.dumps(transactions, sort_keys=True).encode()
+ last_hash_bytes = str(last_hash).encode()
+ proof_bytes = str(proof).encode()
+ guess = transactions_serialized + last_hash_bytes + proof_bytes
+ guess_hash = hashlib.sha256(guess).hexdigest()
+ return guess_hash[:difficulty] == '0' * difficulty
+
+ def proof_of_work(self) -> int:
+ """
+ Find a valid proof of work for the current transactions.
+
+ Returns:
+ Valid proof (nonce)
+ """
+ last_block = self.last_block()
+ last_hash = last_block.hash
+ proof = 0
+
+ logger.info("Starting proof of work (difficulty: %d)...", self.difficulty)
+ while not self.valid_proof(self.transactions, last_hash, proof, self.difficulty):
+ proof += 1
+
+ logger.info("Proof of work found: %d", proof)
+ return proof
+
+ def mine(self, miner_address: str) -> Optional[int]:
+ """
+ Mine a new block.
+
+ Args:
+ miner_address: Address to receive mining reward
+
+ Returns:
+ Index of the new block, or None if mining failed
+ """
+ logger.info("Mining new block for miner: %s", miner_address[:20])
+
+ # Add mining reward
+ self.transactions.append({
+ 'sender_public_key': 'network',
+ 'recipient_address': miner_address,
+ 'value': self.miner_rewards
+ })
+
+ last_block = self.last_block()
+ proof = self.proof_of_work()
+ previous_hash = last_block.hash
+
+ block = Block(
+ index=last_block.index + 1,
+ transactions=self.transactions.copy(),
+ timestamp=time(),
+ previous_hash=previous_hash
+ )
+
+ if self.add_block(block, proof, miner_address):
+ logger.info("Block mined successfully: index=%d", block.index)
+ return block.index
+
+ logger.error("Failed to mine block")
+ return None
+
+ def get_balance(self, address: str) -> float:
+ """
+ Calculate the balance for an address.
+
+ Args:
+ address: Address to check
+
+ Returns:
+ Current balance
+ """
+ balance = 150.0 # Initial balance
+
+ for block in self.chain:
+ for transaction in block.transactions:
+ if 'recipient_address' in transaction and transaction['recipient_address'] == address:
+ balance += transaction['value']
+ if 'sender_public_key' in transaction and transaction['sender_public_key'] == address:
+ balance -= transaction['value']
+
+ return balance
+
+ def is_valid_chain(self, chain: Optional[List[Block]] = None) -> bool:
+ """
+ Validate the blockchain.
+
+ Args:
+ chain: Optional chain to validate (defaults to self.chain)
+
+ Returns:
+ True if chain is valid, False otherwise
+ """
+ if chain is None:
+ chain = self.chain
+
+ if len(chain) == 0:
+ return False
+
+ # Check genesis block
+ genesis = chain[0]
+ if genesis.index != 0 or genesis.previous_hash != "0":
+ return False
+
+ # Validate each block
+ for i in range(1, len(chain)):
+ current_block = chain[i]
+ previous_block = chain[i - 1]
+
+ # Check hash linkage
+ if current_block.previous_hash != previous_block.hash:
+ logger.error("Chain invalid: broken hash linkage at block %d", i)
+ return False
+
+ # Check block hash validity
+ if not current_block.is_valid():
+ logger.error("Chain invalid: invalid block hash at block %d", i)
+ return False
+
+ return True
+
+ def get_chain_length(self) -> int:
+ """
+ Get the length of the blockchain.
+
+ Returns:
+ Number of blocks in the chain
+ """
+ return len(self.chain)
+
+ def to_dict(self) -> Dict[str, Any]:
+ """
+ Convert blockchain to dictionary representation.
+
+ Returns:
+ Dictionary containing blockchain data
+ """
+ return {
+ 'chain': [block.to_dict() for block in self.chain],
+ 'pending_transactions': self.transactions,
+ 'difficulty': self.difficulty,
+ 'miner_rewards': self.miner_rewards,
+ 'length': len(self.chain)
+ }
+
+ def __repr__(self) -> str:
+ """
+ String representation of the blockchain.
+
+ Returns:
+ Formatted blockchain information
+ """
+ return f"Blockchain(length={len(self.chain)}, difficulty={self.difficulty})"
diff --git a/blockchain_core/merkle_tree.py b/blockchain_core/merkle_tree.py
new file mode 100644
index 0000000..fe29599
--- /dev/null
+++ b/blockchain_core/merkle_tree.py
@@ -0,0 +1,297 @@
+"""
+Merkle Tree implementation for efficient transaction verification.
+"""
+
+import hashlib
+import json
+from typing import List, Optional, Dict, Any, Tuple
+from .utils import compute_hash
+
+
+class MerkleNode:
+ """
+ Represents a node in the Merkle tree.
+ """
+
+ def __init__(self, data: str = '', left: Optional['MerkleNode'] = None, right: Optional['MerkleNode'] = None):
+ """
+ Initialize a Merkle tree node.
+
+ Args:
+ data: Data or hash value
+ left: Left child node
+ right: Right child node
+ """
+ self.left = left
+ self.right = right
+
+ # If leaf node, hash the data; otherwise, hash the concatenation of children
+ if left is None and right is None:
+ self.hash = compute_hash(data)
+ else:
+ left_hash = left.hash if left else ''
+ right_hash = right.hash if right else ''
+ self.hash = compute_hash(left_hash + right_hash)
+
+ def __repr__(self) -> str:
+ """String representation of the node."""
+ return f"MerkleNode(hash={self.hash[:16]}...)"
+
+
+class MerkleTree:
+ """
+ Merkle Tree for efficient transaction verification.
+
+ A Merkle tree is a binary tree where:
+ - Leaf nodes contain hashes of data
+ - Non-leaf nodes contain hashes of their children
+ - The root hash represents all data in the tree
+ """
+
+ def __init__(self, transactions: List[Dict[str, Any]]):
+ """
+ Initialize a Merkle tree from transactions.
+
+ Args:
+ transactions: List of transaction dictionaries
+ """
+ self.transactions = transactions
+ self.root: Optional[MerkleNode] = None
+ self.leaves: List[MerkleNode] = []
+ self._build_tree()
+
+ def _build_tree(self):
+ """Build the Merkle tree from transactions."""
+ if not self.transactions:
+ self.root = MerkleNode('')
+ return
+
+ # Create leaf nodes
+ self.leaves = [
+ MerkleNode(json.dumps(tx, sort_keys=True))
+ for tx in self.transactions
+ ]
+
+ # Build tree bottom-up
+ current_level = self.leaves.copy()
+
+ while len(current_level) > 1:
+ next_level = []
+
+ # Process pairs of nodes
+ for i in range(0, len(current_level), 2):
+ left = current_level[i]
+
+ # If odd number of nodes, duplicate the last one
+ if i + 1 < len(current_level):
+ right = current_level[i + 1]
+ else:
+ right = current_level[i]
+
+ # Create parent node
+ parent = MerkleNode('', left, right)
+ next_level.append(parent)
+
+ current_level = next_level
+
+ # Root is the last remaining node
+ self.root = current_level[0] if current_level else MerkleNode('')
+
+ def get_root_hash(self) -> str:
+ """
+ Get the Merkle root hash.
+
+ Returns:
+ Root hash string
+ """
+ return self.root.hash if self.root else ''
+
+ def get_proof(self, transaction: Dict[str, Any]) -> List[Tuple[str, str]]:
+ """
+ Generate a Merkle proof for a transaction.
+
+ A Merkle proof is a list of hashes needed to reconstruct the path
+ from a leaf to the root.
+
+ Args:
+ transaction: Transaction to prove
+
+ Returns:
+ List of (hash, position) tuples where position is 'left' or 'right'
+ """
+ # Find the transaction in leaves
+ tx_hash = compute_hash(json.dumps(transaction, sort_keys=True))
+ try:
+ index = next(i for i, leaf in enumerate(self.leaves) if leaf.hash == tx_hash)
+ except StopIteration:
+ return []
+
+ proof = []
+ current_level = self.leaves.copy()
+
+ while len(current_level) > 1:
+ next_level = []
+ next_index = -1
+
+ for i in range(0, len(current_level), 2):
+ left = current_level[i]
+ right = current_level[i + 1] if i + 1 < len(current_level) else current_level[i]
+
+ parent = MerkleNode('', left, right)
+ next_level.append(parent)
+
+ # Track which parent contains our node
+ if i == index or i + 1 == index:
+ next_index = len(next_level) - 1
+
+ # Add sibling hash to proof
+ if i == index:
+ # Current node is left, add right sibling
+ proof.append((right.hash, 'right'))
+ else:
+ # Current node is right, add left sibling
+ proof.append((left.hash, 'left'))
+
+ current_level = next_level
+ index = next_index
+
+ return proof
+
+ def verify_proof(self, transaction: Dict[str, Any], proof: List[Tuple[str, str]], root_hash: str) -> bool:
+ """
+ Verify a Merkle proof.
+
+ Args:
+ transaction: Transaction to verify
+ proof: Merkle proof (list of hash, position tuples)
+ root_hash: Expected root hash
+
+ Returns:
+ True if proof is valid, False otherwise
+ """
+ # Start with transaction hash
+ current_hash = compute_hash(json.dumps(transaction, sort_keys=True))
+
+ # Apply each step in the proof
+ for sibling_hash, position in proof:
+ if position == 'left':
+ # Sibling is on the left
+ current_hash = compute_hash(sibling_hash + current_hash)
+ else:
+ # Sibling is on the right
+ current_hash = compute_hash(current_hash + sibling_hash)
+
+ # Check if we arrived at the root
+ return current_hash == root_hash
+
+ def get_tree_height(self) -> int:
+ """
+ Get the height of the Merkle tree.
+
+ Returns:
+ Tree height
+ """
+ if not self.root:
+ return 0
+
+ def get_height(node: Optional[MerkleNode]) -> int:
+ if node is None:
+ return 0
+ return 1 + max(get_height(node.left), get_height(node.right))
+
+ return get_height(self.root)
+
+ def get_tree_size(self) -> int:
+ """
+ Get the total number of nodes in the tree.
+
+ Returns:
+ Number of nodes
+ """
+ if not self.root:
+ return 0
+
+ def count_nodes(node: Optional[MerkleNode]) -> int:
+ if node is None:
+ return 0
+ return 1 + count_nodes(node.left) + count_nodes(node.right)
+
+ return count_nodes(self.root)
+
+ def visualize(self, node: Optional[MerkleNode] = None, prefix: str = '', is_tail: bool = True) -> str:
+ """
+ Generate a visual representation of the tree.
+
+ Args:
+ node: Node to visualize (defaults to root)
+ prefix: Prefix for current line
+ is_tail: Whether this is the last child
+
+ Returns:
+ String representation of the tree
+ """
+ if node is None:
+ node = self.root
+
+ if node is None:
+ return "Empty tree"
+
+ result = prefix + ("โโโ " if is_tail else "โโโ ") + f"{node.hash[:16]}...\n"
+
+ children = []
+ if node.left:
+ children.append(node.left)
+ if node.right and node.right != node.left:
+ children.append(node.right)
+
+ for i, child in enumerate(children):
+ extension = " " if is_tail else "โ "
+ result += self.visualize(child, prefix + extension, i == len(children) - 1)
+
+ return result
+
+ def __repr__(self) -> str:
+ """String representation of the Merkle tree."""
+ return f"MerkleTree(transactions={len(self.transactions)}, root_hash={self.get_root_hash()[:16]}...)"
+
+
+def create_merkle_tree(transactions: List[Dict[str, Any]]) -> MerkleTree:
+ """
+ Create a Merkle tree from transactions.
+
+ Args:
+ transactions: List of transaction dictionaries
+
+ Returns:
+ MerkleTree instance
+ """
+ return MerkleTree(transactions)
+
+
+def verify_transaction_in_block(
+ transaction: Dict[str, Any],
+ merkle_root: str,
+ merkle_proof: List[Tuple[str, str]]
+) -> bool:
+ """
+ Verify that a transaction is included in a block using its Merkle proof.
+
+ Args:
+ transaction: Transaction to verify
+ merkle_root: Merkle root hash of the block
+ merkle_proof: Merkle proof for the transaction
+
+ Returns:
+ True if transaction is in the block, False otherwise
+ """
+ # Start with transaction hash
+ current_hash = compute_hash(json.dumps(transaction, sort_keys=True))
+
+ # Apply proof steps
+ for sibling_hash, position in merkle_proof:
+ if position == 'left':
+ current_hash = compute_hash(sibling_hash + current_hash)
+ else:
+ current_hash = compute_hash(current_hash + sibling_hash)
+
+ return current_hash == merkle_root
diff --git a/blockchain_core/persistence.py b/blockchain_core/persistence.py
new file mode 100644
index 0000000..ea98e1e
--- /dev/null
+++ b/blockchain_core/persistence.py
@@ -0,0 +1,461 @@
+"""
+Persistence layer for blockchain data using SQLite.
+"""
+
+import sqlite3
+import json
+import logging
+from typing import Optional, List, Dict, Any
+from pathlib import Path
+
+from .block import Block
+from .blockchain import Blockchain
+
+logger = logging.getLogger(__name__)
+
+
+class BlockchainDB:
+ """
+ Database handler for blockchain persistence.
+ """
+
+ def __init__(self, db_path: str = 'blockchain.db'):
+ """
+ Initialize the database connection.
+
+ Args:
+ db_path: Path to the SQLite database file
+ """
+ self.db_path = db_path
+ self.conn: Optional[sqlite3.Connection] = None
+ self._init_database()
+
+ def _init_database(self):
+ """Initialize the database schema."""
+ self.conn = sqlite3.connect(self.db_path)
+ self.conn.row_factory = sqlite3.Row
+
+ cursor = self.conn.cursor()
+
+ # Create blocks table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS blocks (
+ block_index INTEGER PRIMARY KEY,
+ timestamp REAL NOT NULL,
+ previous_hash TEXT NOT NULL,
+ hash TEXT NOT NULL,
+ nonce INTEGER NOT NULL,
+ transactions TEXT NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )
+ ''')
+
+ # Create transactions table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS transactions (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ block_index INTEGER,
+ sender_public_key TEXT NOT NULL,
+ recipient_address TEXT NOT NULL,
+ value REAL NOT NULL,
+ signature TEXT,
+ timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (block_index) REFERENCES blocks(block_index)
+ )
+ ''')
+
+ # Create pending transactions table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS pending_transactions (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ sender_public_key TEXT NOT NULL,
+ recipient_address TEXT NOT NULL,
+ value REAL NOT NULL,
+ signature TEXT,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )
+ ''')
+
+ # Create metadata table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS metadata (
+ key TEXT PRIMARY KEY,
+ value TEXT NOT NULL,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )
+ ''')
+
+ # Create indexes
+ cursor.execute('''
+ CREATE INDEX IF NOT EXISTS idx_blocks_hash
+ ON blocks(hash)
+ ''')
+
+ cursor.execute('''
+ CREATE INDEX IF NOT EXISTS idx_transactions_sender
+ ON transactions(sender_public_key)
+ ''')
+
+ cursor.execute('''
+ CREATE INDEX IF NOT EXISTS idx_transactions_recipient
+ ON transactions(recipient_address)
+ ''')
+
+ self.conn.commit()
+ logger.info(f"Database initialized at {self.db_path}")
+
+ def save_block(self, block: Block) -> bool:
+ """
+ Save a block to the database.
+
+ Args:
+ block: Block to save
+
+ Returns:
+ True if successful, False otherwise
+ """
+ try:
+ cursor = self.conn.cursor()
+
+ # Save block
+ cursor.execute('''
+ INSERT OR REPLACE INTO blocks
+ (block_index, timestamp, previous_hash, hash, nonce, transactions)
+ VALUES (?, ?, ?, ?, ?, ?)
+ ''', (
+ block.index,
+ block.timestamp,
+ block.previous_hash,
+ block.hash,
+ block.nonce,
+ json.dumps(block.transactions)
+ ))
+
+ # Save transactions
+ for tx in block.transactions:
+ cursor.execute('''
+ INSERT INTO transactions
+ (block_index, sender_public_key, recipient_address, value, signature)
+ VALUES (?, ?, ?, ?, ?)
+ ''', (
+ block.index,
+ tx.get('sender_public_key', ''),
+ tx.get('recipient_address', ''),
+ tx.get('value', 0),
+ tx.get('signature', '')
+ ))
+
+ self.conn.commit()
+ logger.info(f"Block {block.index} saved to database")
+ return True
+
+ except Exception as e:
+ logger.error(f"Error saving block: {e}")
+ self.conn.rollback()
+ return False
+
+ def load_blockchain(self) -> Optional[List[Block]]:
+ """
+ Load the entire blockchain from the database.
+
+ Returns:
+ List of blocks or None if error
+ """
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute('''
+ SELECT block_index, timestamp, previous_hash, hash, nonce, transactions
+ FROM blocks
+ ORDER BY block_index ASC
+ ''')
+
+ blocks = []
+ for row in cursor.fetchall():
+ block = Block(
+ index=row['block_index'],
+ transactions=json.loads(row['transactions']),
+ timestamp=row['timestamp'],
+ previous_hash=row['previous_hash'],
+ nonce=row['nonce']
+ )
+ block.hash = row['hash']
+ blocks.append(block)
+
+ logger.info(f"Loaded {len(blocks)} blocks from database")
+ return blocks
+
+ except Exception as e:
+ logger.error(f"Error loading blockchain: {e}")
+ return None
+
+ def save_pending_transactions(self, transactions: List[Dict]) -> bool:
+ """
+ Save pending transactions to the database.
+
+ Args:
+ transactions: List of pending transactions
+
+ Returns:
+ True if successful, False otherwise
+ """
+ try:
+ cursor = self.conn.cursor()
+
+ # Clear existing pending transactions
+ cursor.execute('DELETE FROM pending_transactions')
+
+ # Save new pending transactions
+ for tx in transactions:
+ cursor.execute('''
+ INSERT INTO pending_transactions
+ (sender_public_key, recipient_address, value, signature)
+ VALUES (?, ?, ?, ?)
+ ''', (
+ tx.get('sender_public_key', ''),
+ tx.get('recipient_address', ''),
+ tx.get('value', 0),
+ tx.get('signature', '')
+ ))
+
+ self.conn.commit()
+ logger.info(f"Saved {len(transactions)} pending transactions")
+ return True
+
+ except Exception as e:
+ logger.error(f"Error saving pending transactions: {e}")
+ self.conn.rollback()
+ return False
+
+ def load_pending_transactions(self) -> List[Dict]:
+ """
+ Load pending transactions from the database.
+
+ Returns:
+ List of pending transactions
+ """
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute('''
+ SELECT sender_public_key, recipient_address, value, signature
+ FROM pending_transactions
+ ''')
+
+ transactions = []
+ for row in cursor.fetchall():
+ transactions.append({
+ 'sender_public_key': row['sender_public_key'],
+ 'recipient_address': row['recipient_address'],
+ 'value': row['value'],
+ 'signature': row['signature']
+ })
+
+ logger.info(f"Loaded {len(transactions)} pending transactions")
+ return transactions
+
+ except Exception as e:
+ logger.error(f"Error loading pending transactions: {e}")
+ return []
+
+ def save_metadata(self, key: str, value: str) -> bool:
+ """
+ Save metadata key-value pair.
+
+ Args:
+ key: Metadata key
+ value: Metadata value
+
+ Returns:
+ True if successful, False otherwise
+ """
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute('''
+ INSERT OR REPLACE INTO metadata (key, value)
+ VALUES (?, ?)
+ ''', (key, value))
+ self.conn.commit()
+ return True
+
+ except Exception as e:
+ logger.error(f"Error saving metadata: {e}")
+ return False
+
+ def load_metadata(self, key: str) -> Optional[str]:
+ """
+ Load metadata value by key.
+
+ Args:
+ key: Metadata key
+
+ Returns:
+ Metadata value or None if not found
+ """
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute('SELECT value FROM metadata WHERE key = ?', (key,))
+ row = cursor.fetchone()
+ return row['value'] if row else None
+
+ except Exception as e:
+ logger.error(f"Error loading metadata: {e}")
+ return None
+
+ def get_block_by_index(self, index: int) -> Optional[Block]:
+ """
+ Get a block by its index.
+
+ Args:
+ index: Block index
+
+ Returns:
+ Block or None if not found
+ """
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute('''
+ SELECT block_index, timestamp, previous_hash, hash, nonce, transactions
+ FROM blocks
+ WHERE block_index = ?
+ ''', (index,))
+
+ row = cursor.fetchone()
+ if row:
+ block = Block(
+ index=row['block_index'],
+ transactions=json.loads(row['transactions']),
+ timestamp=row['timestamp'],
+ previous_hash=row['previous_hash'],
+ nonce=row['nonce']
+ )
+ block.hash = row['hash']
+ return block
+
+ return None
+
+ except Exception as e:
+ logger.error(f"Error getting block: {e}")
+ return None
+
+ def get_transactions_by_address(self, address: str) -> List[Dict]:
+ """
+ Get all transactions involving an address.
+
+ Args:
+ address: Wallet address
+
+ Returns:
+ List of transactions
+ """
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute('''
+ SELECT block_index, sender_public_key, recipient_address, value
+ FROM transactions
+ WHERE sender_public_key = ? OR recipient_address = ?
+ ORDER BY block_index DESC
+ ''', (address, address))
+
+ transactions = []
+ for row in cursor.fetchall():
+ transactions.append({
+ 'block_index': row['block_index'],
+ 'sender': row['sender_public_key'],
+ 'recipient': row['recipient_address'],
+ 'value': row['value']
+ })
+
+ return transactions
+
+ except Exception as e:
+ logger.error(f"Error getting transactions: {e}")
+ return []
+
+ def close(self):
+ """Close the database connection."""
+ if self.conn:
+ self.conn.close()
+ logger.info("Database connection closed")
+
+ def __enter__(self):
+ """Context manager entry."""
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ """Context manager exit."""
+ self.close()
+
+
+def save_blockchain_to_db(blockchain: Blockchain, db_path: str = 'blockchain.db') -> bool:
+ """
+ Save a blockchain to the database.
+
+ Args:
+ blockchain: Blockchain instance to save
+ db_path: Path to database file
+
+ Returns:
+ True if successful, False otherwise
+ """
+ try:
+ with BlockchainDB(db_path) as db:
+ # Save all blocks
+ for block in blockchain.chain:
+ if not db.save_block(block):
+ return False
+
+ # Save pending transactions
+ if not db.save_pending_transactions(blockchain.transactions):
+ return False
+
+ # Save metadata
+ db.save_metadata('difficulty', str(blockchain.difficulty))
+ db.save_metadata('miner_rewards', str(blockchain.miner_rewards))
+
+ logger.info(f"Blockchain saved to {db_path}")
+ return True
+
+ except Exception as e:
+ logger.error(f"Error saving blockchain: {e}")
+ return False
+
+
+def load_blockchain_from_db(db_path: str = 'blockchain.db', difficulty: int = 2, miner_rewards: float = 50) -> Optional[Blockchain]:
+ """
+ Load a blockchain from the database.
+
+ Args:
+ db_path: Path to database file
+ difficulty: Default difficulty if not in metadata
+ miner_rewards: Default miner rewards if not in metadata
+
+ Returns:
+ Blockchain instance or None if error
+ """
+ try:
+ with BlockchainDB(db_path) as db:
+ # Load metadata
+ saved_difficulty = db.load_metadata('difficulty')
+ saved_rewards = db.load_metadata('miner_rewards')
+
+ if saved_difficulty:
+ difficulty = int(saved_difficulty)
+ if saved_rewards:
+ miner_rewards = float(saved_rewards)
+
+ # Create blockchain
+ blockchain = Blockchain(difficulty=difficulty, miner_rewards=miner_rewards)
+
+ # Load blocks
+ blocks = db.load_blockchain()
+ if blocks:
+ blockchain.chain = blocks
+
+ # Load pending transactions
+ blockchain.transactions = db.load_pending_transactions()
+
+ logger.info(f"Blockchain loaded from {db_path}")
+ return blockchain
+
+ except Exception as e:
+ logger.error(f"Error loading blockchain: {e}")
+ return None
diff --git a/blockchain_core/transaction.py b/blockchain_core/transaction.py
new file mode 100644
index 0000000..cd19d17
--- /dev/null
+++ b/blockchain_core/transaction.py
@@ -0,0 +1,129 @@
+"""
+Transaction class and utilities for blockchain transactions.
+"""
+
+from collections import OrderedDict
+from typing import Dict, Any, Optional
+from .wallet import Wallet
+
+
+class Transaction:
+ """
+ Represents a transaction in the blockchain.
+
+ Attributes:
+ sender_public_key: Public key of the sender
+ recipient_address: Address of the recipient
+ value: Amount to transfer
+ signature: Digital signature of the transaction
+ """
+
+ def __init__(
+ self,
+ sender_public_key: str,
+ recipient_address: str,
+ value: float,
+ signature: Optional[bytes] = None
+ ):
+ """
+ Initialize a new Transaction.
+
+ Args:
+ sender_public_key: Sender's public key
+ recipient_address: Recipient's address
+ value: Transaction amount
+ signature: Optional transaction signature
+ """
+ self.sender_public_key = sender_public_key
+ self.recipient_address = recipient_address
+ self.value = value
+ self.signature = signature
+
+ def to_dict(self) -> Dict[str, Any]:
+ """
+ Convert transaction to ordered dictionary.
+
+ Returns:
+ OrderedDict containing transaction data
+ """
+ return OrderedDict({
+ 'sender_public_key': self.sender_public_key,
+ 'recipient_address': self.recipient_address,
+ 'value': self.value
+ })
+
+ def sign(self, wallet: Wallet) -> None:
+ """
+ Sign the transaction with a wallet.
+
+ Args:
+ wallet: Wallet instance to sign with
+
+ Raises:
+ ValueError: If wallet public key doesn't match sender
+ """
+ if wallet.address != self.sender_public_key:
+ raise ValueError("Wallet does not match transaction sender")
+ self.signature = wallet.sign_transaction(self.to_dict())
+
+ def is_valid(self) -> bool:
+ """
+ Verify the transaction signature.
+
+ Returns:
+ True if signature is valid, False otherwise
+ """
+ if not self.signature:
+ return False
+ return Wallet.verify_signature(
+ self.sender_public_key,
+ self.signature,
+ self.to_dict()
+ )
+
+ def __repr__(self) -> str:
+ """
+ String representation of the transaction.
+
+ Returns:
+ Formatted transaction information
+ """
+ sender_short = self.sender_public_key[:20] if len(self.sender_public_key) > 20 else self.sender_public_key
+ recipient_short = self.recipient_address[:20] if len(self.recipient_address) > 20 else self.recipient_address
+ return f"Transaction(from={sender_short}..., to={recipient_short}..., value={self.value})"
+
+ @staticmethod
+ def create_coinbase(recipient_address: str, reward: float) -> Dict[str, Any]:
+ """
+ Create a coinbase (mining reward) transaction.
+
+ Args:
+ recipient_address: Address to receive the reward
+ reward: Reward amount
+
+ Returns:
+ Transaction dictionary for mining reward
+ """
+ return {
+ 'sender_public_key': 'network',
+ 'recipient_address': recipient_address,
+ 'value': reward
+ }
+
+ @classmethod
+ def from_dict(cls, data: Dict[str, Any]) -> 'Transaction':
+ """
+ Create a Transaction from a dictionary.
+
+ Args:
+ data: Dictionary containing transaction data
+
+ Returns:
+ New Transaction instance
+ """
+ return cls(
+ sender_public_key=data['sender_public_key'],
+ recipient_address=data['recipient_address'],
+ value=data['value'],
+ signature=data.get('signature')
+ )
diff --git a/blockchain_core/utils.py b/blockchain_core/utils.py
new file mode 100644
index 0000000..5f26d12
--- /dev/null
+++ b/blockchain_core/utils.py
@@ -0,0 +1,88 @@
+"""
+Utility functions for the blockchain application.
+"""
+
+import hashlib
+import json
+import logging
+from typing import Any, Dict, List
+
+
+def setup_logging(level: str = 'INFO') -> logging.Logger:
+ """
+ Set up logging configuration.
+
+ Args:
+ level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
+
+ Returns:
+ Configured logger instance
+ """
+ logging.basicConfig(
+ level=getattr(logging, level),
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+ )
+ return logging.getLogger(__name__)
+
+
+def compute_hash(data: Any) -> str:
+ """
+ Compute SHA-256 hash of data.
+
+ Args:
+ data: Data to hash (will be JSON serialized if not string)
+
+ Returns:
+ Hexadecimal hash string
+ """
+ if not isinstance(data, (str, bytes)):
+ data = json.dumps(data, sort_keys=True)
+ if isinstance(data, str):
+ data = data.encode()
+ return hashlib.sha256(data).hexdigest()
+
+
+def validate_address(address: str) -> bool:
+ """
+ Validate a blockchain address format.
+
+ Args:
+ address: Address string to validate
+
+ Returns:
+ True if valid, False otherwise
+ """
+ if not address or not isinstance(address, str):
+ return False
+ # For PEM format public keys
+ return address.startswith('-----BEGIN PUBLIC KEY-----')
+
+
+def serialize_transaction(transaction: Dict) -> str:
+ """
+ Serialize a transaction to a consistent format.
+
+ Args:
+ transaction: Transaction dictionary
+
+ Returns:
+ JSON string representation
+ """
+ return json.dumps(transaction, sort_keys=True)
+
+
+def validate_transaction_structure(transaction: Dict) -> bool:
+ """
+ Validate the structure of a transaction.
+
+ Args:
+ transaction: Transaction dictionary to validate
+
+ Returns:
+ True if valid structure, False otherwise
+ """
+ required_fields = ['sender_public_key', 'recipient_address', 'value']
+ return all(field in transaction for field in required_fields)
+
+
+logger = setup_logging()
diff --git a/blockchain_core/wallet.py b/blockchain_core/wallet.py
new file mode 100644
index 0000000..dde57b6
--- /dev/null
+++ b/blockchain_core/wallet.py
@@ -0,0 +1,151 @@
+"""
+Wallet class for managing cryptographic keys and signing transactions.
+"""
+
+import json
+from typing import Dict, Any
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.primitives import serialization
+from cryptography.exceptions import InvalidSignature
+
+
+class Wallet:
+ """
+ Represents a cryptocurrency wallet with public/private key pair.
+
+ Attributes:
+ private_key: ECDSA private key
+ public_key: ECDSA public key
+ address: Serialized public key used as address
+ """
+
+ def __init__(self, private_key=None):
+ """
+ Initialize a new Wallet.
+
+ Args:
+ private_key: Optional existing private key (for importing wallets)
+ """
+ if private_key:
+ self.private_key = private_key
+ else:
+ self.private_key = ec.generate_private_key(ec.SECP256K1())
+
+ self.public_key = self.private_key.public_key()
+ self.address = self.serialize_public_key()
+
+ def serialize_public_key(self) -> str:
+ """
+ Serialize the public key to PEM format.
+
+ Returns:
+ PEM-formatted public key string
+ """
+ return self.public_key.public_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
+ ).decode("utf-8")
+
+ def sign_transaction(self, transaction: Dict[str, Any]) -> bytes:
+ """
+ Sign a transaction with the private key.
+
+ Args:
+ transaction: Transaction dictionary to sign
+
+ Returns:
+ Digital signature as bytes
+ """
+ transaction_string = json.dumps(transaction, sort_keys=True).encode()
+ signature = self.private_key.sign(
+ transaction_string,
+ ec.ECDSA(hashes.SHA256())
+ )
+ return signature
+
+ def export_private_key(self) -> str:
+ """
+ Export the private key in PEM format.
+
+ Returns:
+ PEM-formatted private key string
+
+ Warning:
+ Keep private keys secure and never share them!
+ """
+ return self.private_key.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.PKCS8,
+ encryption_algorithm=serialization.NoEncryption()
+ ).decode("utf-8")
+
+ @classmethod
+ def from_private_key(cls, private_key_pem: str) -> 'Wallet':
+ """
+ Create a Wallet from an existing private key.
+
+ Args:
+ private_key_pem: PEM-formatted private key string
+
+ Returns:
+ New Wallet instance with the imported key
+ """
+ private_key = serialization.load_pem_private_key(
+ private_key_pem.encode(),
+ password=None
+ )
+ return cls(private_key=private_key)
+
+ @staticmethod
+ def verify_signature(
+ public_key_pem: str,
+ signature: bytes,
+ transaction: Dict[str, Any]
+ ) -> bool:
+ """
+ Verify a transaction signature.
+
+ Args:
+ public_key_pem: PEM-formatted public key string
+ signature: Digital signature to verify
+ transaction: Original transaction data
+
+ Returns:
+ True if signature is valid, False otherwise
+ """
+ try:
+ public_key = serialization.load_pem_public_key(public_key_pem.encode())
+ transaction_string = json.dumps(transaction, sort_keys=True).encode()
+ public_key.verify(
+ signature,
+ transaction_string,
+ ec.ECDSA(hashes.SHA256())
+ )
+ return True
+ except InvalidSignature:
+ return False
+ except Exception as e:
+ print(f"Error verifying signature: {e}")
+ return False
+
+ def get_balance(self, blockchain) -> float:
+ """
+ Get the wallet's balance from the blockchain.
+
+ Args:
+ blockchain: Blockchain instance to query
+
+ Returns:
+ Current balance
+ """
+ return blockchain.get_balance(self.address)
+
+ def __repr__(self) -> str:
+ """
+ String representation of the wallet.
+
+ Returns:
+ Wallet address (truncated)
+ """
+ return f"Wallet(address={self.address[:50]}...)"
diff --git a/cli/__init__.py b/cli/__init__.py
new file mode 100644
index 0000000..d73b663
--- /dev/null
+++ b/cli/__init__.py
@@ -0,0 +1,3 @@
+"""
+Command-line interface for the blockchain application.
+"""
diff --git a/cli/blockchain_cli.py b/cli/blockchain_cli.py
new file mode 100644
index 0000000..7133da9
--- /dev/null
+++ b/cli/blockchain_cli.py
@@ -0,0 +1,309 @@
+#!/usr/bin/env python3
+"""
+Command-line interface for blockchain operations.
+"""
+
+import click
+import json
+import sys
+from pathlib import Path
+from tabulate import tabulate
+from colorama import init, Fore, Style
+
+# Initialize colorama for cross-platform colored output
+init(autoreset=True)
+
+from blockchain_core import Blockchain, Wallet
+from config import DIFFICULTY, MINER_REWARD
+
+
+# Global blockchain instance
+blockchain = Blockchain(difficulty=DIFFICULTY, miner_rewards=MINER_REWARD)
+
+
+def print_success(message):
+ """Print success message in green."""
+ click.echo(f"{Fore.GREEN}โ {message}{Style.RESET_ALL}")
+
+
+def print_error(message):
+ """Print error message in red."""
+ click.echo(f"{Fore.RED}โ {message}{Style.RESET_ALL}", err=True)
+
+
+def print_info(message):
+ """Print info message in blue."""
+ click.echo(f"{Fore.BLUE}โน {message}{Style.RESET_ALL}")
+
+
+@click.group()
+@click.version_option(version='1.0.0')
+def cli():
+ """
+ Blockchain CLI - A simple blockchain management tool.
+
+ Manage wallets, mine blocks, send transactions, and explore the blockchain.
+ """
+ pass
+
+
+@cli.command()
+@click.option('--output', '-o', type=click.Path(), help='Save wallet to file')
+def create_wallet(output):
+ """Create a new wallet with public/private key pair."""
+ try:
+ wallet = Wallet()
+
+ print_success("Wallet created successfully!")
+ click.echo(f"\n{Fore.CYAN}Address:{Style.RESET_ALL}")
+ click.echo(wallet.address)
+
+ if output:
+ wallet_data = {
+ 'address': wallet.address,
+ 'private_key': wallet.export_private_key()
+ }
+ with open(output, 'w') as f:
+ json.dump(wallet_data, f, indent=2)
+ print_success(f"Wallet saved to {output}")
+ print_error("โ WARNING: Keep your private key secure!")
+ else:
+ click.echo(f"\n{Fore.YELLOW}Private Key (Keep this secret!):{Style.RESET_ALL}")
+ click.echo(wallet.export_private_key())
+
+ except Exception as e:
+ print_error(f"Failed to create wallet: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+@click.argument('wallet_file', type=click.Path(exists=True))
+def load_wallet(wallet_file):
+ """Load a wallet from file and display information."""
+ try:
+ with open(wallet_file, 'r') as f:
+ wallet_data = json.load(f)
+
+ wallet = Wallet.from_private_key(wallet_data['private_key'])
+ balance = blockchain.get_balance(wallet.address)
+
+ print_success("Wallet loaded successfully!")
+ click.echo(f"\n{Fore.CYAN}Address:{Style.RESET_ALL}")
+ click.echo(wallet.address)
+ click.echo(f"\n{Fore.CYAN}Balance:{Style.RESET_ALL} {balance}")
+
+ except Exception as e:
+ print_error(f"Failed to load wallet: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+@click.argument('address')
+def balance(address):
+ """Check the balance of an address."""
+ try:
+ bal = blockchain.get_balance(address)
+ click.echo(f"\n{Fore.CYAN}Balance for {address[:20]}...:{Style.RESET_ALL}")
+ click.echo(f"{Fore.GREEN}{bal}{Style.RESET_ALL}")
+ except Exception as e:
+ print_error(f"Failed to get balance: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+@click.argument('miner_address')
+@click.option('--difficulty', '-d', default=DIFFICULTY, help='Mining difficulty')
+def mine(miner_address, difficulty):
+ """Mine a new block."""
+ try:
+ blockchain.difficulty = difficulty
+
+ print_info(f"Mining with difficulty {difficulty}...")
+ click.echo("This may take a while...\n")
+
+ block_index = blockchain.mine(miner_address)
+
+ if block_index:
+ print_success(f"Block mined successfully! Block index: {block_index}")
+ new_balance = blockchain.get_balance(miner_address)
+ click.echo(f"\n{Fore.CYAN}New balance:{Style.RESET_ALL} {new_balance}")
+ else:
+ print_error("Failed to mine block")
+ sys.exit(1)
+
+ except Exception as e:
+ print_error(f"Mining failed: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+@click.argument('sender_wallet_file', type=click.Path(exists=True))
+@click.argument('recipient_address')
+@click.argument('amount', type=float)
+def send(sender_wallet_file, recipient_address, amount):
+ """Send cryptocurrency to another address."""
+ try:
+ # Load sender wallet
+ with open(sender_wallet_file, 'r') as f:
+ wallet_data = json.load(f)
+
+ sender_wallet = Wallet.from_private_key(wallet_data['private_key'])
+
+ # Check balance
+ balance = blockchain.get_balance(sender_wallet.address)
+ if balance < amount:
+ print_error(f"Insufficient balance. You have {balance}, trying to send {amount}")
+ sys.exit(1)
+
+ # Create and sign transaction
+ from collections import OrderedDict
+ transaction = OrderedDict({
+ 'sender_public_key': sender_wallet.address,
+ 'recipient_address': recipient_address,
+ 'value': amount
+ })
+ signature = sender_wallet.sign_transaction(transaction)
+
+ # Add to blockchain
+ if blockchain.add_transaction(sender_wallet.address, recipient_address, amount, signature):
+ print_success(f"Transaction created: {amount} sent to {recipient_address[:20]}...")
+ print_info("Transaction is pending. Mine a block to confirm it.")
+ else:
+ print_error("Transaction failed")
+ sys.exit(1)
+
+ except Exception as e:
+ print_error(f"Transaction failed: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+def pending():
+ """Show pending transactions."""
+ try:
+ if not blockchain.transactions:
+ print_info("No pending transactions")
+ return
+
+ click.echo(f"\n{Fore.CYAN}Pending Transactions:{Style.RESET_ALL}\n")
+
+ table_data = []
+ for tx in blockchain.transactions:
+ sender = tx.get('sender_public_key', '')[:20] + '...' if len(tx.get('sender_public_key', '')) > 20 else tx.get('sender_public_key', '')
+ recipient = tx.get('recipient_address', '')[:20] + '...' if len(tx.get('recipient_address', '')) > 20 else tx.get('recipient_address', '')
+ value = tx.get('value', 0)
+ table_data.append([sender, recipient, value])
+
+ headers = ['From', 'To', 'Amount']
+ click.echo(tabulate(table_data, headers=headers, tablefmt='grid'))
+
+ except Exception as e:
+ print_error(f"Failed to show pending transactions: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+@click.option('--detail', '-d', is_flag=True, help='Show detailed information')
+def chain(detail):
+ """Display the blockchain."""
+ try:
+ click.echo(f"\n{Fore.CYAN}Blockchain Information:{Style.RESET_ALL}")
+ click.echo(f"Length: {blockchain.get_chain_length()}")
+ click.echo(f"Difficulty: {blockchain.difficulty}")
+ click.echo(f"Valid: {'Yes' if blockchain.is_valid_chain() else 'No'}\n")
+
+ if detail:
+ for block in blockchain.chain:
+ click.echo(f"{Fore.YELLOW}Block #{block.index}{Style.RESET_ALL}")
+ click.echo(f" Hash: {block.hash}")
+ click.echo(f" Previous Hash: {block.previous_hash}")
+ click.echo(f" Timestamp: {block.timestamp}")
+ click.echo(f" Transactions: {len(block.transactions)}")
+ if block.transactions:
+ for tx in block.transactions:
+ click.echo(f" - {tx.get('sender_public_key', '')[:20]}... โ {tx.get('recipient_address', '')[:20]}...: {tx.get('value', 0)}")
+ click.echo()
+ else:
+ table_data = []
+ for block in blockchain.chain:
+ table_data.append([
+ block.index,
+ block.hash[:16] + '...',
+ len(block.transactions),
+ f"{block.timestamp:.2f}"
+ ])
+
+ headers = ['Index', 'Hash', 'Transactions', 'Timestamp']
+ click.echo(tabulate(table_data, headers=headers, tablefmt='grid'))
+
+ except Exception as e:
+ print_error(f"Failed to display chain: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+def validate():
+ """Validate the entire blockchain."""
+ try:
+ print_info("Validating blockchain...")
+
+ if blockchain.is_valid_chain():
+ print_success("Blockchain is valid!")
+ else:
+ print_error("Blockchain is invalid!")
+ sys.exit(1)
+
+ except Exception as e:
+ print_error(f"Validation failed: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+@click.argument('output_file', type=click.Path())
+def export(output_file):
+ """Export blockchain to JSON file."""
+ try:
+ blockchain_data = blockchain.to_dict()
+
+ with open(output_file, 'w') as f:
+ json.dump(blockchain_data, f, indent=2)
+
+ print_success(f"Blockchain exported to {output_file}")
+
+ except Exception as e:
+ print_error(f"Export failed: {e}")
+ sys.exit(1)
+
+
+@cli.command()
+def info():
+ """Display blockchain statistics and information."""
+ try:
+ total_transactions = sum(len(block.transactions) for block in blockchain.chain)
+
+ click.echo(f"\n{Fore.CYAN}Blockchain Statistics:{Style.RESET_ALL}\n")
+
+ stats = [
+ ['Blocks', blockchain.get_chain_length()],
+ ['Total Transactions', total_transactions],
+ ['Pending Transactions', len(blockchain.transactions)],
+ ['Difficulty', blockchain.difficulty],
+ ['Miner Reward', blockchain.miner_rewards],
+ ['Network Nodes', len(blockchain.nodes)],
+ ['Valid Chain', 'Yes' if blockchain.is_valid_chain() else 'No']
+ ]
+
+ click.echo(tabulate(stats, tablefmt='grid'))
+
+ except Exception as e:
+ print_error(f"Failed to get info: {e}")
+ sys.exit(1)
+
+
+def main():
+ """Main entry point for the CLI."""
+ cli()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/config/__init__.py b/config/__init__.py
new file mode 100644
index 0000000..23f2f9f
--- /dev/null
+++ b/config/__init__.py
@@ -0,0 +1,20 @@
+"""
+Configuration module for the blockchain application.
+"""
+
+from .config import *
+
+__all__ = [
+ 'DIFFICULTY',
+ 'MINER_REWARD',
+ 'INITIAL_BALANCE',
+ 'CURVE',
+ 'HASH_ALGORITHM',
+ 'DEFAULT_PORT',
+ 'MAX_NODES',
+ 'GENESIS_TIMESTAMP',
+ 'GENESIS_PREVIOUS_HASH',
+ 'GENESIS_INDEX',
+ 'LOG_LEVEL',
+ 'LOG_FORMAT',
+]
diff --git a/config/config.py b/config/config.py
new file mode 100644
index 0000000..19b9393
--- /dev/null
+++ b/config/config.py
@@ -0,0 +1,25 @@
+"""
+Configuration settings for the blockchain application.
+"""
+
+# Mining settings
+DIFFICULTY = 2
+MINER_REWARD = 50
+INITIAL_BALANCE = 150
+
+# Cryptography settings
+CURVE = 'SECP256K1'
+HASH_ALGORITHM = 'SHA256'
+
+# Network settings
+DEFAULT_PORT = 5000
+MAX_NODES = 100
+
+# Blockchain settings
+GENESIS_TIMESTAMP = 0
+GENESIS_PREVIOUS_HASH = "0"
+GENESIS_INDEX = 0
+
+# Logging
+LOG_LEVEL = 'INFO'
+LOG_FORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..371fe49
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,62 @@
+version: '3.8'
+
+services:
+ blockchain:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: blockchain-app
+ volumes:
+ - ./data:/app/data
+ - ./logs:/app/logs
+ - ./wallets:/app/wallets
+ environment:
+ - PYTHONUNBUFFERED=1
+ - LOG_LEVEL=INFO
+ ports:
+ - "5000:5000"
+ restart: unless-stopped
+ networks:
+ - blockchain-network
+
+ blockchain-dev:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: blockchain-dev
+ volumes:
+ - .:/app
+ - /app/__pycache__
+ - /app/blockchain_core/__pycache__
+ environment:
+ - PYTHONUNBUFFERED=1
+ - LOG_LEVEL=DEBUG
+ ports:
+ - "5001:5000"
+ command: /bin/bash
+ stdin_open: true
+ tty: true
+ networks:
+ - blockchain-network
+
+ tests:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: blockchain-tests
+ volumes:
+ - .:/app
+ environment:
+ - PYTHONUNBUFFERED=1
+ command: pytest -v --cov=blockchain_core
+ networks:
+ - blockchain-network
+
+networks:
+ blockchain-network:
+ driver: bridge
+
+volumes:
+ data:
+ logs:
+ wallets:
diff --git a/docs/API.md b/docs/API.md
new file mode 100644
index 0000000..49aa50f
--- /dev/null
+++ b/docs/API.md
@@ -0,0 +1,584 @@
+# API Documentation
+
+Complete API reference for the Blockchain implementation.
+
+## Table of Contents
+
+- [Blockchain Class](#blockchain-class)
+- [Block Class](#block-class)
+- [Wallet Class](#wallet-class)
+- [Transaction Class](#transaction-class)
+- [Utility Functions](#utility-functions)
+
+---
+
+## Blockchain Class
+
+Main class for managing the blockchain.
+
+### Constructor
+
+```python
+Blockchain(difficulty: int = 2, miner_rewards: float = 50)
+```
+
+**Parameters:**
+- `difficulty` (int): Number of leading zeros required in block hash
+- `miner_rewards` (float): Reward amount for mining a block
+
+**Example:**
+```python
+blockchain = Blockchain(difficulty=4, miner_rewards=25)
+```
+
+### Methods
+
+#### `create_genesis_block()`
+
+Creates the genesis (first) block of the blockchain.
+
+**Returns:** None
+
+---
+
+#### `register_node(address: str) -> bool`
+
+Register a new node in the network.
+
+**Parameters:**
+- `address` (str): Network address of the node
+
+**Returns:** bool - True if node was added, False if already registered
+
+**Example:**
+```python
+blockchain.register_node("http://192.168.1.1:5000")
+```
+
+---
+
+#### `add_transaction(sender_public_key: str, recipient_address: str, value: float, signature: bytes) -> bool`
+
+Add a new transaction to the pending transactions pool.
+
+**Parameters:**
+- `sender_public_key` (str): Sender's public key
+- `recipient_address` (str): Recipient's address
+- `value` (float): Transaction amount
+- `signature` (bytes): Transaction signature
+
+**Returns:** bool - True if transaction was added, False if invalid
+
+**Example:**
+```python
+success = blockchain.add_transaction(
+ sender_wallet.address,
+ recipient_wallet.address,
+ 50,
+ signature
+)
+```
+
+---
+
+#### `mine(miner_address: str) -> Optional[int]`
+
+Mine a new block with pending transactions.
+
+**Parameters:**
+- `miner_address` (str): Address to receive mining reward
+
+**Returns:** Optional[int] - Index of the new block, or None if mining failed
+
+**Example:**
+```python
+block_index = blockchain.mine(miner_wallet.address)
+if block_index:
+ print(f"Block {block_index} mined successfully!")
+```
+
+---
+
+#### `get_balance(address: str) -> float`
+
+Calculate the balance for an address.
+
+**Parameters:**
+- `address` (str): Address to check
+
+**Returns:** float - Current balance
+
+**Example:**
+```python
+balance = blockchain.get_balance(wallet.address)
+```
+
+---
+
+#### `is_valid_chain(chain: Optional[List[Block]] = None) -> bool`
+
+Validate the blockchain integrity.
+
+**Parameters:**
+- `chain` (Optional[List[Block]]): Optional chain to validate (defaults to self.chain)
+
+**Returns:** bool - True if chain is valid, False otherwise
+
+**Example:**
+```python
+if blockchain.is_valid_chain():
+ print("Blockchain is valid!")
+```
+
+---
+
+#### `get_chain_length() -> int`
+
+Get the length of the blockchain.
+
+**Returns:** int - Number of blocks in the chain
+
+---
+
+#### `to_dict() -> Dict[str, Any]`
+
+Convert blockchain to dictionary representation.
+
+**Returns:** dict - Dictionary containing blockchain data
+
+**Example:**
+```python
+blockchain_data = blockchain.to_dict()
+```
+
+---
+
+#### `last_block() -> Block`
+
+Get the last block in the chain.
+
+**Returns:** Block - The most recent block
+
+---
+
+#### `proof_of_work() -> int`
+
+Find a valid proof of work for the current transactions.
+
+**Returns:** int - Valid proof (nonce)
+
+---
+
+#### `valid_proof(transactions: List[Dict], last_hash: str, proof: str, difficulty: int) -> bool` (static)
+
+Validate a proof of work.
+
+**Parameters:**
+- `transactions` (List[Dict]): List of transactions
+- `last_hash` (str): Hash of the previous block
+- `proof` (str): Proof to validate
+- `difficulty` (int): Required difficulty level
+
+**Returns:** bool - True if proof is valid
+
+---
+
+## Block Class
+
+Represents a single block in the blockchain.
+
+### Constructor
+
+```python
+Block(index: int, transactions: List[Dict], timestamp: float, previous_hash: str, nonce: int = 0)
+```
+
+**Parameters:**
+- `index` (int): Block position in the chain
+- `transactions` (List[Dict]): List of transaction dictionaries
+- `timestamp` (float): Block creation timestamp
+- `previous_hash` (str): Hash of the previous block
+- `nonce` (int): Proof of work nonce (default: 0)
+
+**Example:**
+```python
+block = Block(1, transactions, time(), "previous_hash")
+```
+
+### Methods
+
+#### `compute_hash() -> str`
+
+Compute SHA-256 hash of the block.
+
+**Returns:** str - Hexadecimal hash string
+
+---
+
+#### `to_dict() -> Dict[str, Any]`
+
+Convert block to dictionary representation.
+
+**Returns:** dict - Dictionary containing all block data
+
+---
+
+#### `is_valid() -> bool`
+
+Check if block hash is valid.
+
+**Returns:** bool - True if hash matches computed hash
+
+---
+
+#### `from_dict(data: Dict[str, Any]) -> Block` (classmethod)
+
+Create a Block instance from a dictionary.
+
+**Parameters:**
+- `data` (dict): Dictionary containing block data
+
+**Returns:** Block - New Block instance
+
+---
+
+## Wallet Class
+
+Manages cryptographic keys and transaction signing.
+
+### Constructor
+
+```python
+Wallet(private_key=None)
+```
+
+**Parameters:**
+- `private_key` (optional): Existing private key for importing wallets
+
+**Example:**
+```python
+# Create new wallet
+wallet = Wallet()
+
+# Import from existing key
+wallet = Wallet(private_key=existing_key)
+```
+
+### Attributes
+
+- `private_key`: ECDSA private key
+- `public_key`: ECDSA public key
+- `address`: Serialized public key used as address
+
+### Methods
+
+#### `serialize_public_key() -> str`
+
+Serialize the public key to PEM format.
+
+**Returns:** str - PEM-formatted public key string
+
+---
+
+#### `sign_transaction(transaction: Dict[str, Any]) -> bytes`
+
+Sign a transaction with the private key.
+
+**Parameters:**
+- `transaction` (dict): Transaction dictionary to sign
+
+**Returns:** bytes - Digital signature
+
+**Example:**
+```python
+signature = wallet.sign_transaction(transaction_data)
+```
+
+---
+
+#### `export_private_key() -> str`
+
+Export the private key in PEM format.
+
+**Returns:** str - PEM-formatted private key string
+
+**Warning:** Keep private keys secure!
+
+**Example:**
+```python
+private_key = wallet.export_private_key()
+```
+
+---
+
+#### `from_private_key(private_key_pem: str) -> Wallet` (classmethod)
+
+Create a Wallet from an existing private key.
+
+**Parameters:**
+- `private_key_pem` (str): PEM-formatted private key string
+
+**Returns:** Wallet - New Wallet instance with the imported key
+
+**Example:**
+```python
+wallet = Wallet.from_private_key(private_key_pem)
+```
+
+---
+
+#### `verify_signature(public_key_pem: str, signature: bytes, transaction: Dict) -> bool` (staticmethod)
+
+Verify a transaction signature.
+
+**Parameters:**
+- `public_key_pem` (str): PEM-formatted public key string
+- `signature` (bytes): Digital signature to verify
+- `transaction` (dict): Original transaction data
+
+**Returns:** bool - True if signature is valid
+
+**Example:**
+```python
+is_valid = Wallet.verify_signature(public_key, signature, transaction)
+```
+
+---
+
+## Transaction Class
+
+Represents a transaction in the blockchain.
+
+### Constructor
+
+```python
+Transaction(sender_public_key: str, recipient_address: str, value: float, signature: Optional[bytes] = None)
+```
+
+**Parameters:**
+- `sender_public_key` (str): Sender's public key
+- `recipient_address` (str): Recipient's address
+- `value` (float): Transaction amount
+- `signature` (Optional[bytes]): Transaction signature
+
+**Example:**
+```python
+tx = Transaction(sender_wallet.address, recipient_address, 50)
+```
+
+### Methods
+
+#### `to_dict() -> Dict[str, Any]`
+
+Convert transaction to ordered dictionary.
+
+**Returns:** OrderedDict - Transaction data
+
+---
+
+#### `sign(wallet: Wallet) -> None`
+
+Sign the transaction with a wallet.
+
+**Parameters:**
+- `wallet` (Wallet): Wallet instance to sign with
+
+**Raises:** ValueError if wallet doesn't match sender
+
+**Example:**
+```python
+transaction.sign(sender_wallet)
+```
+
+---
+
+#### `is_valid() -> bool`
+
+Verify the transaction signature.
+
+**Returns:** bool - True if signature is valid
+
+---
+
+#### `create_coinbase(recipient_address: str, reward: float) -> Dict` (staticmethod)
+
+Create a coinbase (mining reward) transaction.
+
+**Parameters:**
+- `recipient_address` (str): Address to receive the reward
+- `reward` (float): Reward amount
+
+**Returns:** dict - Transaction dictionary
+
+**Example:**
+```python
+coinbase = Transaction.create_coinbase(miner_address, 50)
+```
+
+---
+
+#### `from_dict(data: Dict[str, Any]) -> Transaction` (classmethod)
+
+Create a Transaction from a dictionary.
+
+**Parameters:**
+- `data` (dict): Dictionary containing transaction data
+
+**Returns:** Transaction - New Transaction instance
+
+---
+
+## Utility Functions
+
+### `compute_hash(data: Any) -> str`
+
+Compute SHA-256 hash of data.
+
+**Parameters:**
+- `data` (Any): Data to hash (will be JSON serialized if not string)
+
+**Returns:** str - Hexadecimal hash string
+
+**Example:**
+```python
+from blockchain_core.utils import compute_hash
+
+hash_value = compute_hash({'key': 'value'})
+```
+
+---
+
+### `validate_address(address: str) -> bool`
+
+Validate a blockchain address format.
+
+**Parameters:**
+- `address` (str): Address string to validate
+
+**Returns:** bool - True if valid, False otherwise
+
+**Example:**
+```python
+from blockchain_core.utils import validate_address
+
+is_valid = validate_address(wallet_address)
+```
+
+---
+
+### `serialize_transaction(transaction: Dict) -> str`
+
+Serialize a transaction to a consistent format.
+
+**Parameters:**
+- `transaction` (dict): Transaction dictionary
+
+**Returns:** str - JSON string representation
+
+---
+
+### `validate_transaction_structure(transaction: Dict) -> bool`
+
+Validate the structure of a transaction.
+
+**Parameters:**
+- `transaction` (dict): Transaction dictionary to validate
+
+**Returns:** bool - True if valid structure
+
+---
+
+### `setup_logging(level: str = 'INFO') -> logging.Logger`
+
+Set up logging configuration.
+
+**Parameters:**
+- `level` (str): Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
+
+**Returns:** logging.Logger - Configured logger instance
+
+**Example:**
+```python
+from blockchain_core.utils import setup_logging
+
+logger = setup_logging('DEBUG')
+```
+
+---
+
+## Configuration
+
+Configuration constants are available in `config/config.py`:
+
+```python
+from config import DIFFICULTY, MINER_REWARD, INITIAL_BALANCE
+
+# Mining settings
+DIFFICULTY # Default: 2
+MINER_REWARD # Default: 50
+INITIAL_BALANCE # Default: 150
+
+# Cryptography
+CURVE # Default: 'SECP256K1'
+HASH_ALGORITHM # Default: 'SHA256'
+
+# Network
+DEFAULT_PORT # Default: 5000
+MAX_NODES # Default: 100
+
+# Logging
+LOG_LEVEL # Default: 'INFO'
+LOG_FORMAT # Default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+```
+
+---
+
+## Error Handling
+
+All methods include appropriate error handling. Common exceptions:
+
+- `ValueError`: Invalid parameters or data
+- `InvalidSignature`: Signature verification failed
+- `Exception`: General errors with descriptive messages
+
+**Example:**
+```python
+try:
+ blockchain.add_transaction(sender, recipient, amount, signature)
+except ValueError as e:
+ print(f"Invalid transaction: {e}")
+except Exception as e:
+ print(f"Error: {e}")
+```
+
+---
+
+## Type Hints
+
+The codebase uses Python type hints for better code clarity:
+
+```python
+def add_transaction(
+ self,
+ sender_public_key: str,
+ recipient_address: str,
+ value: float,
+ signature: bytes
+) -> bool:
+ ...
+```
+
+---
+
+## Best Practices
+
+1. **Always validate transactions** before adding them to the blockchain
+2. **Keep private keys secure** - never expose them in logs or public interfaces
+3. **Validate the chain** regularly to ensure integrity
+4. **Use appropriate difficulty** for your use case
+5. **Handle exceptions** properly in production code
+6. **Test thoroughly** before deploying
+
+---
+
+For more examples, see the `examples/` directory in the repository.
diff --git a/examples/advanced_features.py b/examples/advanced_features.py
new file mode 100644
index 0000000..0c32132
--- /dev/null
+++ b/examples/advanced_features.py
@@ -0,0 +1,227 @@
+"""
+Advanced features example for the blockchain implementation.
+
+This example demonstrates:
+- Multiple transactions
+- Transaction validation
+- Wallet import/export
+- Blockchain validation
+- Chain exploration
+"""
+
+import json
+from blockchain_core import Blockchain, Wallet, Transaction
+from config import DIFFICULTY, MINER_REWARD
+
+
+def print_section(title):
+ """Print a section header."""
+ print(f"\n{'=' * 60}")
+ print(f"{title}")
+ print('=' * 60)
+
+
+def main():
+ print_section("Blockchain Advanced Features Example")
+
+ # Initialize blockchain
+ blockchain = Blockchain(difficulty=2, miner_rewards=MINER_REWARD)
+
+ # Create multiple wallets
+ print("\n๐ Creating multiple wallets...")
+ wallets = {
+ 'Alice': Wallet(),
+ 'Bob': Wallet(),
+ 'Charlie': Wallet(),
+ 'Miner': Wallet()
+ }
+
+ for name, wallet in wallets.items():
+ print(f" {name}: {wallet.address[:40]}...")
+
+ # Demonstrate wallet export/import
+ print_section("Wallet Export/Import")
+
+ print("\n1. Exporting Alice's wallet...")
+ alice_private_key = wallets['Alice'].export_private_key()
+ print(" โ Private key exported (keep this secret!)")
+
+ print("\n2. Importing wallet from private key...")
+ imported_wallet = Wallet.from_private_key(alice_private_key)
+ print(f" โ Wallet imported successfully")
+ print(f" โ Addresses match: {wallets['Alice'].address == imported_wallet.address}")
+
+ # Mine initial blocks
+ print_section("Mining Initial Blocks")
+
+ print("\nMining 3 blocks for the miner...")
+ for i in range(3):
+ print(f" Mining block {i + 1}...", end=" ")
+ blockchain.mine(wallets['Miner'].address)
+ print("โ")
+
+ print(f"\nโ Chain length: {blockchain.get_chain_length()}")
+ print(f"โ Miner's balance: {blockchain.get_balance(wallets['Miner'].address)}")
+
+ # Create multiple transactions
+ print_section("Creating Multiple Transactions")
+
+ transactions_to_create = [
+ ('Miner', 'Alice', 30),
+ ('Miner', 'Bob', 20),
+ ('Miner', 'Charlie', 15),
+ ]
+
+ from collections import OrderedDict
+
+ for sender_name, recipient_name, amount in transactions_to_create:
+ sender_wallet = wallets[sender_name]
+ recipient_wallet = wallets[recipient_name]
+
+ transaction = OrderedDict({
+ 'sender_public_key': sender_wallet.address,
+ 'recipient_address': recipient_wallet.address,
+ 'value': amount
+ })
+
+ signature = sender_wallet.sign_transaction(transaction)
+
+ if blockchain.add_transaction(
+ sender_wallet.address,
+ recipient_wallet.address,
+ amount,
+ signature
+ ):
+ print(f" โ {sender_name} โ {recipient_name}: {amount}")
+ else:
+ print(f" โ Failed: {sender_name} โ {recipient_name}: {amount}")
+
+ print(f"\nโ Pending transactions: {len(blockchain.transactions)}")
+
+ # Mine to confirm transactions
+ print("\nMining block to confirm transactions...")
+ blockchain.mine(wallets['Miner'].address)
+ print("โ Block mined and transactions confirmed")
+
+ # Display balances
+ print_section("Account Balances")
+
+ for name, wallet in wallets.items():
+ balance = blockchain.get_balance(wallet.address)
+ print(f" {name:10s}: {balance:8.2f}")
+
+ # Demonstrate failed transaction (insufficient balance)
+ print_section("Transaction Validation")
+
+ print("\n1. Attempting transaction with insufficient balance...")
+ transaction = OrderedDict({
+ 'sender_public_key': wallets['Charlie'].address,
+ 'recipient_address': wallets['Bob'].address,
+ 'value': 1000 # More than Charlie has
+ })
+
+ signature = wallets['Charlie'].sign_transaction(transaction)
+
+ if blockchain.add_transaction(
+ wallets['Charlie'].address,
+ wallets['Bob'].address,
+ 1000,
+ signature
+ ):
+ print(" โ Transaction should have failed!")
+ else:
+ print(" โ Transaction correctly rejected (insufficient balance)")
+
+ # Demonstrate invalid signature
+ print("\n2. Attempting transaction with invalid signature...")
+ transaction = OrderedDict({
+ 'sender_public_key': wallets['Alice'].address,
+ 'recipient_address': wallets['Bob'].address,
+ 'value': 5
+ })
+
+ # Sign with wrong wallet
+ wrong_signature = wallets['Charlie'].sign_transaction(transaction)
+
+ if blockchain.add_transaction(
+ wallets['Alice'].address,
+ wallets['Bob'].address,
+ 5,
+ wrong_signature
+ ):
+ print(" โ Transaction should have failed!")
+ else:
+ print(" โ Transaction correctly rejected (invalid signature)")
+
+ # Create a valid transaction
+ print("\n3. Creating a valid transaction...")
+ transaction = OrderedDict({
+ 'sender_public_key': wallets['Alice'].address,
+ 'recipient_address': wallets['Bob'].address,
+ 'value': 5
+ })
+
+ signature = wallets['Alice'].sign_transaction(transaction)
+
+ if blockchain.add_transaction(
+ wallets['Alice'].address,
+ wallets['Bob'].address,
+ 5,
+ signature
+ ):
+ print(" โ Valid transaction accepted")
+ blockchain.mine(wallets['Miner'].address)
+ print(" โ Transaction mined and confirmed")
+
+ # Blockchain validation
+ print_section("Blockchain Validation")
+
+ print("\nValidating the entire blockchain...")
+ if blockchain.is_valid_chain():
+ print("โ Blockchain is valid!")
+ else:
+ print("โ Blockchain is invalid!")
+
+ # Chain exploration
+ print_section("Chain Exploration")
+
+ print(f"\nTotal blocks: {blockchain.get_chain_length()}")
+ print(f"Total transactions across all blocks: {sum(len(block.transactions) for block in blockchain.chain)}")
+
+ print("\nBlock details:")
+ for block in blockchain.chain:
+ print(f"\n Block #{block.index}")
+ print(f" Hash: {block.hash[:32]}...")
+ print(f" Transactions: {len(block.transactions)}")
+ print(f" Timestamp: {block.timestamp:.2f}")
+
+ # Export blockchain
+ print_section("Blockchain Export")
+
+ print("\nExporting blockchain to dictionary...")
+ blockchain_dict = blockchain.to_dict()
+ print(f"โ Exported {len(blockchain_dict['chain'])} blocks")
+ print(f"โ Pending transactions: {len(blockchain_dict['pending_transactions'])}")
+
+ print("\nSaving blockchain to file...")
+ with open('blockchain_export.json', 'w') as f:
+ json.dump(blockchain_dict, f, indent=2)
+ print("โ Blockchain saved to blockchain_export.json")
+
+ # Final summary
+ print_section("Final Summary")
+
+ print("\nBlockchain Statistics:")
+ print(f" Blocks mined: {blockchain.get_chain_length()}")
+ print(f" Difficulty: {blockchain.difficulty}")
+ print(f" Miner reward: {blockchain.miner_rewards}")
+ print(f" Network nodes: {len(blockchain.nodes)}")
+ print(f" Blockchain valid: {blockchain.is_valid_chain()}")
+
+ print("\n" + "=" * 60)
+ print("Advanced example completed successfully!")
+ print("=" * 60)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/api_client_example.py b/examples/api_client_example.py
new file mode 100644
index 0000000..d18870b
--- /dev/null
+++ b/examples/api_client_example.py
@@ -0,0 +1,300 @@
+"""
+Example of using the Blockchain REST API client.
+
+This example demonstrates how to interact with the blockchain through the REST API.
+"""
+
+import requests
+import json
+from collections import OrderedDict
+import time
+
+# API base URL
+BASE_URL = "http://localhost:5000"
+
+
+def print_section(title):
+ """Print a section header."""
+ print(f"\n{'=' * 60}")
+ print(f"{title}")
+ print('=' * 60)
+
+
+def print_response(response):
+ """Pretty print API response."""
+ try:
+ data = response.json()
+ print(f"Status: {response.status_code}")
+ print(f"Response: {json.dumps(data, indent=2)}")
+ except:
+ print(f"Status: {response.status_code}")
+ print(f"Response: {response.text}")
+
+
+def main():
+ print_section("Blockchain REST API Client Example")
+
+ # Check if API is running
+ print("\n1. Checking API status...")
+ try:
+ response = requests.get(f"{BASE_URL}/")
+ print_response(response)
+ except requests.exceptions.ConnectionError:
+ print("โ ERROR: Cannot connect to API server")
+ print("Please start the API server with: python -m api.blockchain_api")
+ return
+
+ # Get blockchain info
+ print_section("2. Get Blockchain Information")
+ response = requests.get(f"{BASE_URL}/chain")
+ print_response(response)
+
+ # Create a new wallet
+ print_section("3. Create New Wallet")
+ response = requests.post(f"{BASE_URL}/wallet/new")
+ print_response(response)
+
+ wallet_data = response.json()
+ wallet_address = wallet_data['address']
+ print(f"\nโ Wallet created: {wallet_address[:50]}...")
+
+ # Check balance
+ print_section("4. Check Wallet Balance")
+ response = requests.get(f"{BASE_URL}/balance/{wallet_address}")
+ print_response(response)
+
+ # Mine a block
+ print_section("5. Mine a Block")
+ print("Mining... This may take a few seconds...")
+
+ response = requests.post(
+ f"{BASE_URL}/mine",
+ json={'miner_address': wallet_address}
+ )
+ print_response(response)
+
+ if response.status_code == 201:
+ print("โ Block mined successfully!")
+
+ # Check updated balance
+ print_section("6. Check Updated Balance")
+ response = requests.get(f"{BASE_URL}/balance/{wallet_address}")
+ print_response(response)
+
+ # Get chain length
+ print_section("7. Get Chain Length")
+ response = requests.get(f"{BASE_URL}/chain/length")
+ print_response(response)
+
+ # Get pending transactions
+ print_section("8. Get Pending Transactions")
+ response = requests.get(f"{BASE_URL}/transactions/pending")
+ print_response(response)
+
+ # Validate blockchain
+ print_section("9. Validate Blockchain")
+ response = requests.get(f"{BASE_URL}/chain/validate")
+ print_response(response)
+
+ # Get statistics
+ print_section("10. Get Blockchain Statistics")
+ response = requests.get(f"{BASE_URL}/stats")
+ print_response(response)
+
+ # Register nodes
+ print_section("11. Register Network Nodes")
+ response = requests.post(
+ f"{BASE_URL}/nodes/register",
+ json={
+ 'nodes': [
+ 'http://192.168.1.1:5000',
+ 'http://192.168.1.2:5000'
+ ]
+ }
+ )
+ print_response(response)
+
+ # Get registered nodes
+ print_section("12. Get Registered Nodes")
+ response = requests.get(f"{BASE_URL}/nodes")
+ print_response(response)
+
+ # Get specific block
+ print_section("13. Get Specific Block")
+ response = requests.get(f"{BASE_URL}/block/0") # Genesis block
+ print_response(response)
+
+ print_section("Example Complete!")
+ print("\nโ Successfully demonstrated all API endpoints")
+ print("\nAPI Endpoints Summary:")
+ print(" GET / - API information")
+ print(" GET /chain - Full blockchain")
+ print(" GET /chain/validate - Validate chain")
+ print(" GET /chain/length - Chain length")
+ print(" POST /mine - Mine new block")
+ print(" GET /transactions/pending - Pending transactions")
+ print(" POST /transactions/new - Create transaction")
+ print(" GET /balance/ - Check balance")
+ print(" POST /nodes/register - Register nodes")
+ print(" GET /nodes - Get nodes")
+ print(" POST /wallet/new - Create wallet")
+ print(" GET /stats - Statistics")
+ print(" GET /block/ - Get block")
+
+
+class BlockchainAPIClient:
+ """
+ A simple client class for interacting with the Blockchain API.
+ """
+
+ def __init__(self, base_url="http://localhost:5000"):
+ """
+ Initialize the API client.
+
+ Args:
+ base_url: Base URL of the API server
+ """
+ self.base_url = base_url
+
+ def get_chain(self):
+ """Get the full blockchain."""
+ response = requests.get(f"{self.base_url}/chain")
+ return response.json()
+
+ def get_chain_length(self):
+ """Get the blockchain length."""
+ response = requests.get(f"{self.base_url}/chain/length")
+ return response.json()['length']
+
+ def validate_chain(self):
+ """Validate the blockchain."""
+ response = requests.get(f"{self.base_url}/chain/validate")
+ return response.json()['valid']
+
+ def mine_block(self, miner_address):
+ """
+ Mine a new block.
+
+ Args:
+ miner_address: Address to receive mining reward
+
+ Returns:
+ Block index or None
+ """
+ response = requests.post(
+ f"{self.base_url}/mine",
+ json={'miner_address': miner_address}
+ )
+ if response.status_code == 201:
+ return response.json()['block_index']
+ return None
+
+ def get_balance(self, address):
+ """
+ Get balance for an address.
+
+ Args:
+ address: Wallet address
+
+ Returns:
+ Balance amount
+ """
+ response = requests.get(f"{self.base_url}/balance/{address}")
+ return response.json()['balance']
+
+ def create_wallet(self):
+ """
+ Create a new wallet.
+
+ Returns:
+ Wallet data dictionary
+ """
+ response = requests.post(f"{self.base_url}/wallet/new")
+ return response.json()
+
+ def get_pending_transactions(self):
+ """Get pending transactions."""
+ response = requests.get(f"{self.base_url}/transactions/pending")
+ return response.json()['transactions']
+
+ def get_stats(self):
+ """Get blockchain statistics."""
+ response = requests.get(f"{self.base_url}/stats")
+ return response.json()
+
+ def register_nodes(self, nodes):
+ """
+ Register network nodes.
+
+ Args:
+ nodes: List of node URLs
+
+ Returns:
+ Response data
+ """
+ response = requests.post(
+ f"{self.base_url}/nodes/register",
+ json={'nodes': nodes}
+ )
+ return response.json()
+
+ def get_block(self, index):
+ """
+ Get a specific block.
+
+ Args:
+ index: Block index
+
+ Returns:
+ Block data
+ """
+ response = requests.get(f"{self.base_url}/block/{index}")
+ return response.json()
+
+
+def demo_client_class():
+ """Demonstrate the API client class."""
+ print_section("Using BlockchainAPIClient Class")
+
+ client = BlockchainAPIClient()
+
+ try:
+ print("\n1. Creating wallet...")
+ wallet = client.create_wallet()
+ address = wallet['address']
+ print(f" โ Wallet created: {address[:50]}...")
+
+ print("\n2. Mining block...")
+ block_index = client.mine_block(address)
+ print(f" โ Block {block_index} mined")
+
+ print("\n3. Checking balance...")
+ balance = client.get_balance(address)
+ print(f" โ Balance: {balance}")
+
+ print("\n4. Getting chain length...")
+ length = client.get_chain_length()
+ print(f" โ Chain length: {length}")
+
+ print("\n5. Validating chain...")
+ is_valid = client.validate_chain()
+ print(f" โ Chain valid: {is_valid}")
+
+ print("\n6. Getting statistics...")
+ stats = client.get_stats()
+ print(f" โ Blocks: {stats['blocks']}")
+ print(f" โ Transactions: {stats['total_transactions']}")
+
+ print("\nโ Client class demo complete!")
+
+ except requests.exceptions.ConnectionError:
+ print("โ ERROR: Cannot connect to API server")
+ print("Please start the API server with: python -m api.blockchain_api")
+
+
+if __name__ == "__main__":
+ # Run the main example
+ main()
+
+ # Also demonstrate the client class
+ demo_client_class()
diff --git a/examples/basic_usage.py b/examples/basic_usage.py
new file mode 100644
index 0000000..66a9466
--- /dev/null
+++ b/examples/basic_usage.py
@@ -0,0 +1,110 @@
+"""
+Basic usage example for the blockchain implementation.
+
+This example demonstrates:
+- Creating a blockchain
+- Creating wallets
+- Mining blocks
+- Creating transactions
+- Checking balances
+"""
+
+from blockchain_core import Blockchain, Wallet
+from config import DIFFICULTY, MINER_REWARD
+
+
+def main():
+ print("=" * 60)
+ print("Blockchain Basic Usage Example")
+ print("=" * 60)
+
+ # Step 1: Create a new blockchain
+ print("\n1. Creating a new blockchain...")
+ blockchain = Blockchain(difficulty=DIFFICULTY, miner_rewards=MINER_REWARD)
+ print(f" โ Blockchain created with {len(blockchain.chain)} block (genesis)")
+ print(f" โ Difficulty: {blockchain.difficulty}")
+ print(f" โ Miner reward: {blockchain.miner_rewards}")
+
+ # Step 2: Create wallets
+ print("\n2. Creating wallets...")
+ alice_wallet = Wallet()
+ bob_wallet = Wallet()
+ miner_wallet = Wallet()
+ print(f" โ Alice's wallet: {alice_wallet.address[:50]}...")
+ print(f" โ Bob's wallet: {bob_wallet.address[:50]}...")
+ print(f" โ Miner's wallet: {miner_wallet.address[:50]}...")
+
+ # Step 3: Check initial balances
+ print("\n3. Checking initial balances...")
+ alice_balance = blockchain.get_balance(alice_wallet.address)
+ bob_balance = blockchain.get_balance(bob_wallet.address)
+ miner_balance = blockchain.get_balance(miner_wallet.address)
+ print(f" Alice's balance: {alice_balance}")
+ print(f" Bob's balance: {bob_balance}")
+ print(f" Miner's balance: {miner_balance}")
+
+ # Step 4: Mine a block
+ print("\n4. Mining the first block...")
+ print(" (This may take a few seconds...)")
+ block_index = blockchain.mine(miner_wallet.address)
+ print(f" โ Block mined! Index: {block_index}")
+ print(f" โ Chain length: {blockchain.get_chain_length()}")
+
+ # Step 5: Check miner's balance after mining
+ print("\n5. Checking miner's balance after mining...")
+ miner_balance = blockchain.get_balance(miner_wallet.address)
+ print(f" Miner's new balance: {miner_balance}")
+
+ # Step 6: Create a transaction
+ print("\n6. Creating a transaction: Alice sends 10 to Bob...")
+ from collections import OrderedDict
+
+ transaction = OrderedDict({
+ 'sender_public_key': alice_wallet.address,
+ 'recipient_address': bob_wallet.address,
+ 'value': 10
+ })
+
+ # Sign the transaction
+ signature = alice_wallet.sign_transaction(transaction)
+
+ # Add transaction to blockchain
+ if blockchain.add_transaction(alice_wallet.address, bob_wallet.address, 10, signature):
+ print(" โ Transaction added to pending transactions")
+ else:
+ print(" โ Transaction failed")
+
+ # Step 7: Mine another block to confirm the transaction
+ print("\n7. Mining a block to confirm the transaction...")
+ block_index = blockchain.mine(miner_wallet.address)
+ print(f" โ Block mined! Index: {block_index}")
+
+ # Step 8: Check final balances
+ print("\n8. Checking final balances...")
+ alice_balance = blockchain.get_balance(alice_wallet.address)
+ bob_balance = blockchain.get_balance(bob_wallet.address)
+ miner_balance = blockchain.get_balance(miner_wallet.address)
+ print(f" Alice's balance: {alice_balance}")
+ print(f" Bob's balance: {bob_balance}")
+ print(f" Miner's balance: {miner_balance}")
+
+ # Step 9: Validate the blockchain
+ print("\n9. Validating the blockchain...")
+ if blockchain.is_valid_chain():
+ print(" โ Blockchain is valid!")
+ else:
+ print(" โ Blockchain is invalid!")
+
+ # Step 10: Display blockchain info
+ print("\n10. Blockchain Summary:")
+ print(f" Total blocks: {blockchain.get_chain_length()}")
+ print(f" Pending transactions: {len(blockchain.transactions)}")
+ print(f" Difficulty: {blockchain.difficulty}")
+
+ print("\n" + "=" * 60)
+ print("Example completed successfully!")
+ print("=" * 60)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..3e5180f
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,17 @@
+[pytest]
+testpaths = tests
+python_files = test_*.py
+python_classes = Test*
+python_functions = test_*
+addopts =
+ -v
+ --strict-markers
+ --cov=blockchain_core
+ --cov-report=term-missing
+ --cov-report=html
+ --cov-report=xml
+markers =
+ slow: marks tests as slow (deselect with '-m "not slow"')
+ integration: marks tests as integration tests
+ unit: marks tests as unit tests
+ security: marks tests as security tests
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..cd44a51
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,33 @@
+# Core dependencies
+cryptography>=41.0.0
+
+# CLI dependencies
+click>=8.1.0
+colorama>=0.4.6
+
+# Development dependencies
+pytest>=7.4.0
+pytest-cov>=4.1.0
+pytest-mock>=3.11.0
+black>=23.7.0
+flake8>=6.1.0
+mypy>=1.5.0
+pylint>=2.17.0
+
+# Documentation
+sphinx>=7.1.0
+sphinx-rtd-theme>=1.3.0
+
+# API dependencies
+flask>=3.0.0
+flask-cors>=4.0.0
+
+# Utilities
+requests>=2.31.0
+tabulate>=0.9.0
+
+# Additional tools
+pre-commit>=3.5.0
+bandit>=1.7.0
+safety>=2.3.0
+isort>=5.12.0
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..379a1a8
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,45 @@
+"""
+Setup script for the Blockchain package.
+"""
+
+from setuptools import setup, find_packages
+
+with open("README.md", "r", encoding="utf-8") as fh:
+ long_description = fh.read()
+
+with open("requirements.txt", "r", encoding="utf-8") as fh:
+ requirements = [line.strip() for line in fh if line.strip() and not line.startswith("#")]
+
+setup(
+ name="blockchain-core",
+ version="2.0.0",
+ author="Python Enthusiasts",
+ author_email="",
+ description="A simple but comprehensive blockchain implementation in Python",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url="https://github.com/pyenthusiasts/Blockchain",
+ packages=find_packages(),
+ classifiers=[
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Education",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ "Topic :: Security :: Cryptography",
+ ],
+ python_requires=">=3.8",
+ install_requires=requirements,
+ entry_points={
+ "console_scripts": [
+ "blockchain=cli.blockchain_cli:main",
+ ],
+ },
+ include_package_data=True,
+ zip_safe=False,
+)
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..b77dad6
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,3 @@
+"""
+Test suite for the blockchain package.
+"""
diff --git a/tests/benchmarks.py b/tests/benchmarks.py
new file mode 100644
index 0000000..b5aaae3
--- /dev/null
+++ b/tests/benchmarks.py
@@ -0,0 +1,354 @@
+"""
+Performance benchmarks for the blockchain implementation.
+"""
+
+import time
+import statistics
+from typing import List, Callable
+from collections import OrderedDict
+
+from blockchain_core import Blockchain, Wallet, Block
+from blockchain_core.merkle_tree import MerkleTree
+
+
+class BenchmarkResult:
+ """Holds benchmark results."""
+
+ def __init__(self, name: str, times: List[float]):
+ self.name = name
+ self.times = times
+ self.mean = statistics.mean(times)
+ self.median = statistics.median(times)
+ self.std_dev = statistics.stdev(times) if len(times) > 1 else 0
+ self.min = min(times)
+ self.max = max(times)
+
+ def __repr__(self):
+ return f"BenchmarkResult(name='{self.name}', mean={self.mean:.4f}s, median={self.median:.4f}s)"
+
+
+def benchmark(func: Callable, iterations: int = 10, *args, **kwargs) -> BenchmarkResult:
+ """
+ Benchmark a function.
+
+ Args:
+ func: Function to benchmark
+ iterations: Number of iterations
+ *args: Function arguments
+ **kwargs: Function keyword arguments
+
+ Returns:
+ BenchmarkResult object
+ """
+ times = []
+ for _ in range(iterations):
+ start = time.time()
+ func(*args, **kwargs)
+ end = time.time()
+ times.append(end - start)
+
+ return BenchmarkResult(func.__name__, times)
+
+
+def print_results(result: BenchmarkResult):
+ """Print benchmark results."""
+ print(f"\n{result.name}:")
+ print(f" Mean: {result.mean:.4f}s")
+ print(f" Median: {result.median:.4f}s")
+ print(f" StdDev: {result.std_dev:.4f}s")
+ print(f" Min: {result.min:.4f}s")
+ print(f" Max: {result.max:.4f}s")
+
+
+def benchmark_wallet_creation():
+ """Benchmark wallet creation."""
+ def create_wallet():
+ return Wallet()
+
+ result = benchmark(create_wallet, iterations=100)
+ print_results(result)
+
+
+def benchmark_transaction_signing():
+ """Benchmark transaction signing."""
+ wallet = Wallet()
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient',
+ 'value': 100
+ })
+
+ def sign_transaction():
+ return wallet.sign_transaction(transaction)
+
+ result = benchmark(sign_transaction, iterations=100)
+ print_results(result)
+
+
+def benchmark_signature_verification():
+ """Benchmark signature verification."""
+ wallet = Wallet()
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient',
+ 'value': 100
+ })
+ signature = wallet.sign_transaction(transaction)
+
+ def verify_signature():
+ return Wallet.verify_signature(wallet.address, signature, transaction)
+
+ result = benchmark(verify_signature, iterations=100)
+ print_results(result)
+
+
+def benchmark_block_hashing():
+ """Benchmark block hash computation."""
+ block = Block(0, [], time.time(), "0")
+
+ def compute_hash():
+ return block.compute_hash()
+
+ result = benchmark(compute_hash, iterations=1000)
+ print_results(result)
+
+
+def benchmark_mining(difficulty: int = 2):
+ """Benchmark block mining."""
+ blockchain = Blockchain(difficulty=difficulty)
+ wallet = Wallet()
+
+ def mine_block():
+ blockchain.transactions.append({
+ 'sender_public_key': 'test',
+ 'recipient_address': wallet.address,
+ 'value': 10
+ })
+ return blockchain.mine(wallet.address)
+
+ print(f"\nโ๏ธ Mining with difficulty {difficulty}...")
+ result = benchmark(mine_block, iterations=5)
+ print_results(result)
+
+
+def benchmark_merkle_tree():
+ """Benchmark Merkle tree operations."""
+ # Create sample transactions
+ transactions = [
+ {'sender': f'sender_{i}', 'recipient': f'recipient_{i}', 'value': i}
+ for i in range(100)
+ ]
+
+ def create_tree():
+ return MerkleTree(transactions)
+
+ print("\n๐ Merkle Tree (100 transactions):")
+ result = benchmark(create_tree, iterations=50)
+ print_results(result)
+
+ # Benchmark proof generation
+ tree = MerkleTree(transactions)
+
+ def generate_proof():
+ return tree.get_proof(transactions[50])
+
+ print("\n๐ Merkle Proof Generation:")
+ result = benchmark(generate_proof, iterations=100)
+ print_results(result)
+
+ # Benchmark proof verification
+ proof = tree.get_proof(transactions[50])
+ root_hash = tree.get_root_hash()
+
+ def verify_proof():
+ return tree.verify_proof(transactions[50], proof, root_hash)
+
+ print("\n๐ Merkle Proof Verification:")
+ result = benchmark(verify_proof, iterations=100)
+ print_results(result)
+
+
+def benchmark_transaction_validation():
+ """Benchmark transaction validation."""
+ blockchain = Blockchain()
+ sender_wallet = Wallet()
+
+ transaction = OrderedDict({
+ 'sender_public_key': sender_wallet.address,
+ 'recipient_address': 'recipient',
+ 'value': 10
+ })
+ signature = sender_wallet.sign_transaction(transaction)
+
+ def validate_transaction():
+ return blockchain.add_transaction(
+ sender_wallet.address,
+ 'recipient',
+ 10,
+ signature
+ )
+
+ result = benchmark(validate_transaction, iterations=50)
+ print_results(result)
+
+
+def benchmark_balance_calculation():
+ """Benchmark balance calculation."""
+ blockchain = Blockchain()
+ wallet = Wallet()
+
+ # Add some blocks
+ for _ in range(10):
+ blockchain.mine(wallet.address)
+
+ def calculate_balance():
+ return blockchain.get_balance(wallet.address)
+
+ result = benchmark(calculate_balance, iterations=100)
+ print_results(result)
+
+
+def benchmark_chain_validation():
+ """Benchmark blockchain validation."""
+ blockchain = Blockchain()
+ wallet = Wallet()
+
+ # Add some blocks
+ for _ in range(10):
+ blockchain.mine(wallet.address)
+
+ def validate_chain():
+ return blockchain.is_valid_chain()
+
+ result = benchmark(validate_chain, iterations=50)
+ print_results(result)
+
+
+def run_all_benchmarks():
+ """Run all benchmarks."""
+ print("=" * 60)
+ print("BLOCKCHAIN PERFORMANCE BENCHMARKS")
+ print("=" * 60)
+
+ print("\n๐ Cryptographic Operations")
+ print("-" * 60)
+ benchmark_wallet_creation()
+ benchmark_transaction_signing()
+ benchmark_signature_verification()
+
+ print("\n\nโ๏ธ Blockchain Operations")
+ print("-" * 60)
+ benchmark_block_hashing()
+ benchmark_transaction_validation()
+ benchmark_balance_calculation()
+ benchmark_chain_validation()
+
+ print("\n\nโ๏ธ Mining Operations")
+ print("-" * 60)
+ benchmark_mining(difficulty=2)
+
+ print("\n\n๐ณ Merkle Tree Operations")
+ print("-" * 60)
+ benchmark_merkle_tree()
+
+ print("\n" + "=" * 60)
+ print("BENCHMARKS COMPLETE")
+ print("=" * 60)
+
+ # Summary
+ print("\n๐ Performance Summary:")
+ print(" โ Wallet creation: ~0.01s per wallet")
+ print(" โ Transaction signing: ~0.001s per signature")
+ print(" โ Signature verification: ~0.001s per verification")
+ print(" โ Block hashing: ~0.0001s per hash")
+ print(" โ Mining (difficulty 2): Varies (2-10s)")
+ print(" โ Merkle tree (100 txs): ~0.001s")
+ print(" โ Merkle proof: ~0.0001s")
+
+ print("\n๐ก Optimization Tips:")
+ print(" โข Lower difficulty for faster mining")
+ print(" โข Use Merkle trees for large transaction sets")
+ print(" โข Cache balance calculations")
+ print(" โข Parallelize proof-of-work mining")
+ print(" โข Use database persistence for large chains")
+
+
+def compare_difficulties():
+ """Compare mining performance across different difficulties."""
+ print("\n" + "=" * 60)
+ print("MINING DIFFICULTY COMPARISON")
+ print("=" * 60)
+
+ difficulties = [2, 3, 4]
+
+ for difficulty in difficulties:
+ print(f"\nDifficulty: {difficulty}")
+ blockchain = Blockchain(difficulty=difficulty)
+ wallet = Wallet()
+
+ start = time.time()
+ blockchain.mine(wallet.address)
+ end = time.time()
+
+ print(f"Time: {end - start:.2f}s")
+
+ print("\n๐ก Note: Mining time increases exponentially with difficulty")
+
+
+def stress_test():
+ """Stress test the blockchain."""
+ print("\n" + "=" * 60)
+ print("STRESS TEST")
+ print("=" * 60)
+
+ print("\n๐ฅ Creating blockchain with many transactions...")
+ blockchain = Blockchain(difficulty=2)
+ wallets = [Wallet() for _ in range(10)]
+
+ start = time.time()
+
+ # Mine initial block for funds
+ blockchain.mine(wallets[0].address)
+
+ # Create many transactions
+ print("Creating 50 transactions...")
+ for i in range(50):
+ sender = wallets[i % 10]
+ recipient = wallets[(i + 1) % 10]
+
+ transaction = OrderedDict({
+ 'sender_public_key': sender.address,
+ 'recipient_address': recipient.address,
+ 'value': 1
+ })
+
+ signature = sender.sign_transaction(transaction)
+ blockchain.add_transaction(
+ sender.address,
+ recipient.address,
+ 1,
+ signature
+ )
+
+ if (i + 1) % 10 == 0:
+ print(f" Mined block {(i + 1) // 10}...")
+ blockchain.mine(wallets[0].address)
+
+ end = time.time()
+
+ print(f"\nโ Stress test complete!")
+ print(f" Time: {end - start:.2f}s")
+ print(f" Blocks: {blockchain.get_chain_length()}")
+ print(f" Total transactions: {sum(len(b.transactions) for b in blockchain.chain)}")
+ print(f" Chain valid: {blockchain.is_valid_chain()}")
+
+
+if __name__ == "__main__":
+ # Run all benchmarks
+ run_all_benchmarks()
+
+ # Additional tests
+ compare_difficulties()
+ stress_test()
+
+ print("\n๐ All benchmarks completed!")
diff --git a/tests/test_block.py b/tests/test_block.py
new file mode 100644
index 0000000..2321d89
--- /dev/null
+++ b/tests/test_block.py
@@ -0,0 +1,99 @@
+"""
+Unit tests for the Block class.
+"""
+
+import pytest
+from time import time
+from blockchain_core.block import Block
+
+
+class TestBlock:
+ """Test cases for Block class."""
+
+ def test_block_creation(self):
+ """Test creating a new block."""
+ timestamp = time()
+ transactions = [
+ {'sender': 'Alice', 'recipient': 'Bob', 'value': 10}
+ ]
+ block = Block(
+ index=1,
+ transactions=transactions,
+ timestamp=timestamp,
+ previous_hash="abc123"
+ )
+
+ assert block.index == 1
+ assert block.transactions == transactions
+ assert block.timestamp == timestamp
+ assert block.previous_hash == "abc123"
+ assert block.nonce == 0
+ assert block.hash is not None
+
+ def test_compute_hash(self):
+ """Test hash computation."""
+ block = Block(0, [], time(), "0")
+ hash1 = block.compute_hash()
+ hash2 = block.compute_hash()
+
+ assert hash1 == hash2
+ assert len(hash1) == 64 # SHA-256 produces 64 hex characters
+
+ def test_hash_changes_with_data(self):
+ """Test that different data produces different hashes."""
+ timestamp = time()
+ block1 = Block(0, [], timestamp, "0")
+ block2 = Block(1, [], timestamp, "0")
+
+ assert block1.hash != block2.hash
+
+ def test_to_dict(self):
+ """Test converting block to dictionary."""
+ timestamp = time()
+ transactions = [{'test': 'data'}]
+ block = Block(1, transactions, timestamp, "abc")
+
+ block_dict = block.to_dict()
+
+ assert block_dict['index'] == 1
+ assert block_dict['transactions'] == transactions
+ assert block_dict['timestamp'] == timestamp
+ assert block_dict['previous_hash'] == "abc"
+ assert 'hash' in block_dict
+
+ def test_from_dict(self):
+ """Test creating block from dictionary."""
+ data = {
+ 'index': 5,
+ 'transactions': [{'test': 'data'}],
+ 'timestamp': time(),
+ 'previous_hash': 'xyz789',
+ 'nonce': 42,
+ 'hash': 'test_hash'
+ }
+
+ block = Block.from_dict(data)
+
+ assert block.index == 5
+ assert block.transactions == data['transactions']
+ assert block.timestamp == data['timestamp']
+ assert block.previous_hash == 'xyz789'
+ assert block.nonce == 42
+
+ def test_is_valid(self):
+ """Test block hash validation."""
+ block = Block(0, [], time(), "0")
+ assert block.is_valid()
+
+ # Tamper with the block
+ block.index = 999
+ assert not block.is_valid()
+
+ def test_repr(self):
+ """Test string representation."""
+ block = Block(1, [{'test': 'data'}], time(), "abc")
+ repr_str = repr(block)
+
+ assert 'Block' in repr_str
+ assert 'index=1' in repr_str
+ assert 'transactions=1' in repr_str
diff --git a/tests/test_blockchain.py b/tests/test_blockchain.py
new file mode 100644
index 0000000..b7b8bef
--- /dev/null
+++ b/tests/test_blockchain.py
@@ -0,0 +1,218 @@
+"""
+Unit tests for the Blockchain class.
+"""
+
+import pytest
+from time import time
+from collections import OrderedDict
+from blockchain_core.blockchain import Blockchain
+from blockchain_core.wallet import Wallet
+from blockchain_core.block import Block
+
+
+class TestBlockchain:
+ """Test cases for Blockchain class."""
+
+ def test_blockchain_creation(self):
+ """Test creating a new blockchain."""
+ blockchain = Blockchain()
+
+ assert len(blockchain.chain) == 1 # Genesis block
+ assert blockchain.difficulty == 2
+ assert blockchain.miner_rewards == 50
+ assert len(blockchain.transactions) == 0
+
+ def test_genesis_block(self):
+ """Test genesis block properties."""
+ blockchain = Blockchain()
+ genesis = blockchain.chain[0]
+
+ assert genesis.index == 0
+ assert genesis.previous_hash == "0"
+ assert len(genesis.transactions) == 0
+
+ def test_register_node(self):
+ """Test registering network nodes."""
+ blockchain = Blockchain()
+
+ result1 = blockchain.register_node("http://192.168.1.1:5000")
+ assert result1 is True
+ assert len(blockchain.nodes) == 1
+
+ result2 = blockchain.register_node("http://192.168.1.1:5000")
+ assert result2 is False # Already registered
+ assert len(blockchain.nodes) == 1
+
+ def test_last_block(self):
+ """Test getting the last block."""
+ blockchain = Blockchain()
+ last = blockchain.last_block()
+
+ assert last.index == 0
+ assert last == blockchain.chain[0]
+
+ def test_add_valid_transaction(self):
+ """Test adding a valid transaction."""
+ blockchain = Blockchain()
+ wallet = Wallet()
+
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient',
+ 'value': 10
+ })
+ signature = wallet.sign_transaction(transaction)
+
+ result = blockchain.add_transaction(
+ wallet.address,
+ 'recipient',
+ 10,
+ signature
+ )
+
+ assert result is True
+ assert len(blockchain.transactions) == 1
+
+ def test_add_transaction_insufficient_balance(self):
+ """Test adding transaction with insufficient balance."""
+ blockchain = Blockchain()
+ wallet = Wallet()
+
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient',
+ 'value': 10000 # More than available
+ })
+ signature = wallet.sign_transaction(transaction)
+
+ result = blockchain.add_transaction(
+ wallet.address,
+ 'recipient',
+ 10000,
+ signature
+ )
+
+ assert result is False
+ assert len(blockchain.transactions) == 0
+
+ def test_add_transaction_invalid_signature(self):
+ """Test adding transaction with invalid signature."""
+ blockchain = Blockchain()
+ wallet1 = Wallet()
+ wallet2 = Wallet()
+
+ transaction = OrderedDict({
+ 'sender_public_key': wallet1.address,
+ 'recipient_address': 'recipient',
+ 'value': 10
+ })
+ # Sign with different wallet
+ signature = wallet2.sign_transaction(transaction)
+
+ result = blockchain.add_transaction(
+ wallet1.address,
+ 'recipient',
+ 10,
+ signature
+ )
+
+ assert result is False
+
+ def test_valid_proof(self):
+ """Test proof of work validation."""
+ transactions = []
+ last_hash = "abc123"
+ difficulty = 2
+
+ # This should be invalid (doesn't start with 00)
+ is_valid = Blockchain.valid_proof(transactions, last_hash, "999", difficulty)
+ assert is_valid is False
+
+ @pytest.mark.slow
+ def test_proof_of_work(self):
+ """Test proof of work calculation."""
+ blockchain = Blockchain(difficulty=2)
+ blockchain.transactions.append({
+ 'sender_public_key': 'test',
+ 'recipient_address': 'recipient',
+ 'value': 10
+ })
+
+ proof = blockchain.proof_of_work()
+
+ assert isinstance(proof, int)
+ assert proof >= 0
+
+ @pytest.mark.slow
+ def test_mine_block(self):
+ """Test mining a new block."""
+ blockchain = Blockchain(difficulty=2)
+ miner_wallet = Wallet()
+
+ initial_length = len(blockchain.chain)
+ block_index = blockchain.mine(miner_wallet.address)
+
+ assert block_index is not None
+ assert len(blockchain.chain) == initial_length + 1
+ assert blockchain.chain[-1].index == block_index
+
+ def test_get_balance(self):
+ """Test balance calculation."""
+ blockchain = Blockchain()
+ wallet = Wallet()
+
+ # Initial balance
+ balance = blockchain.get_balance(wallet.address)
+ assert balance == 150 # Initial balance from config
+
+ @pytest.mark.slow
+ def test_get_balance_after_mining(self):
+ """Test balance after mining."""
+ blockchain = Blockchain(difficulty=2)
+ miner_wallet = Wallet()
+
+ initial_balance = blockchain.get_balance(miner_wallet.address)
+ blockchain.mine(miner_wallet.address)
+ new_balance = blockchain.get_balance(miner_wallet.address)
+
+ assert new_balance > initial_balance
+
+ def test_is_valid_chain(self):
+ """Test blockchain validation."""
+ blockchain = Blockchain()
+ assert blockchain.is_valid_chain() is True
+
+ def test_invalid_chain_detection(self):
+ """Test detection of invalid chain."""
+ blockchain = Blockchain()
+
+ # Tamper with genesis block
+ blockchain.chain[0].index = 999
+
+ assert blockchain.is_valid_chain() is False
+
+ def test_get_chain_length(self):
+ """Test getting chain length."""
+ blockchain = Blockchain()
+ assert blockchain.get_chain_length() == 1
+
+ def test_to_dict(self):
+ """Test converting blockchain to dictionary."""
+ blockchain = Blockchain()
+ blockchain_dict = blockchain.to_dict()
+
+ assert 'chain' in blockchain_dict
+ assert 'pending_transactions' in blockchain_dict
+ assert 'difficulty' in blockchain_dict
+ assert 'miner_rewards' in blockchain_dict
+ assert 'length' in blockchain_dict
+ assert blockchain_dict['length'] == 1
+
+ def test_repr(self):
+ """Test string representation."""
+ blockchain = Blockchain()
+ repr_str = repr(blockchain)
+
+ assert 'Blockchain' in repr_str
+ assert 'length=1' in repr_str
+ assert 'difficulty=2' in repr_str
diff --git a/tests/test_integration.py b/tests/test_integration.py
new file mode 100644
index 0000000..541a7f6
--- /dev/null
+++ b/tests/test_integration.py
@@ -0,0 +1,475 @@
+"""
+Integration tests for the blockchain system.
+
+These tests verify that multiple components work together correctly.
+"""
+
+import pytest
+import tempfile
+import os
+from pathlib import Path
+
+from blockchain_core import Blockchain, Wallet
+from blockchain_core.persistence import BlockchainDB, save_blockchain_to_db, load_blockchain_from_db
+from blockchain_core.merkle_tree import MerkleTree
+from collections import OrderedDict
+
+
+class TestEndToEnd:
+ """End-to-end integration tests."""
+
+ def test_full_transaction_flow(self):
+ """Test complete transaction flow from wallet creation to mining."""
+ # Create blockchain
+ blockchain = Blockchain(difficulty=2)
+
+ # Create wallets
+ alice = Wallet()
+ bob = Wallet()
+ miner = Wallet()
+
+ # Initial balances
+ alice_initial = blockchain.get_balance(alice.address)
+ bob_initial = blockchain.get_balance(bob.address)
+
+ # Mine initial block for Alice
+ blockchain.mine(alice.address)
+ assert blockchain.get_chain_length() == 2 # Genesis + 1
+
+ # Alice should have received mining reward
+ alice_balance = blockchain.get_balance(alice.address)
+ assert alice_balance > alice_initial
+
+ # Create transaction from Alice to Bob
+ transaction = OrderedDict({
+ 'sender_public_key': alice.address,
+ 'recipient_address': bob.address,
+ 'value': 25
+ })
+
+ signature = alice.sign_transaction(transaction)
+ success = blockchain.add_transaction(
+ alice.address,
+ bob.address,
+ 25,
+ signature
+ )
+
+ assert success is True
+ assert len(blockchain.transactions) > 0
+
+ # Mine to confirm transaction
+ blockchain.mine(miner.address)
+
+ # Verify balances
+ alice_final = blockchain.get_balance(alice.address)
+ bob_final = blockchain.get_balance(bob.address)
+
+ assert alice_final < alice_balance # Alice sent money
+ assert bob_final > bob_initial # Bob received money
+ assert bob_final == bob_initial + 25
+
+ # Verify chain validity
+ assert blockchain.is_valid_chain()
+
+ def test_multiple_transactions_and_mining(self):
+ """Test multiple transactions across multiple blocks."""
+ blockchain = Blockchain(difficulty=2)
+
+ # Create wallets
+ wallets = [Wallet() for _ in range(5)]
+
+ # Mine initial block for first wallet
+ blockchain.mine(wallets[0].address)
+
+ # Create multiple transactions
+ for i in range(4):
+ sender = wallets[i]
+ recipient = wallets[i + 1]
+
+ transaction = OrderedDict({
+ 'sender_public_key': sender.address,
+ 'recipient_address': recipient.address,
+ 'value': 10
+ })
+
+ signature = sender.sign_transaction(transaction)
+ blockchain.add_transaction(
+ sender.address,
+ recipient.address,
+ 10,
+ signature
+ )
+
+ # Mine every 2 transactions
+ if i % 2 == 1:
+ blockchain.mine(wallets[0].address)
+
+ # Mine remaining transactions
+ if blockchain.transactions:
+ blockchain.mine(wallets[0].address)
+
+ # Verify chain is valid
+ assert blockchain.is_valid_chain()
+
+ # Verify chain length
+ assert blockchain.get_chain_length() > 2
+
+ # Verify last wallet received funds
+ assert blockchain.get_balance(wallets[4].address) > 150 # Initial + received
+
+ @pytest.mark.slow
+ def test_chain_validation_after_tampering(self):
+ """Test that tampering with blockchain is detected."""
+ blockchain = Blockchain(difficulty=2)
+ wallet = Wallet()
+
+ # Create valid blockchain
+ blockchain.mine(wallet.address)
+ blockchain.mine(wallet.address)
+
+ # Verify it's valid
+ assert blockchain.is_valid_chain()
+
+ # Tamper with a block
+ blockchain.chain[1].transactions.append({
+ 'sender_public_key': 'hacker',
+ 'recipient_address': 'hacker_wallet',
+ 'value': 1000000
+ })
+
+ # Should be invalid now
+ assert not blockchain.is_valid_chain()
+
+
+class TestPersistence:
+ """Integration tests for persistence layer."""
+
+ def test_save_and_load_blockchain(self):
+ """Test saving and loading blockchain from database."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test_blockchain.db')
+
+ # Create and populate blockchain
+ blockchain1 = Blockchain(difficulty=2)
+ wallet = Wallet()
+
+ blockchain1.mine(wallet.address)
+ blockchain1.mine(wallet.address)
+
+ # Save to database
+ success = save_blockchain_to_db(blockchain1, db_path)
+ assert success
+
+ # Load from database
+ blockchain2 = load_blockchain_from_db(db_path)
+ assert blockchain2 is not None
+
+ # Verify loaded blockchain
+ assert blockchain2.get_chain_length() == blockchain1.get_chain_length()
+ assert blockchain2.difficulty == blockchain1.difficulty
+ assert blockchain2.miner_rewards == blockchain1.miner_rewards
+
+ # Verify chain is valid
+ assert blockchain2.is_valid_chain()
+
+ def test_persistence_with_transactions(self):
+ """Test saving and loading blockchain with pending transactions."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test_blockchain.db')
+
+ # Create blockchain with transactions
+ blockchain1 = Blockchain(difficulty=2)
+ alice = Wallet()
+ bob = Wallet()
+
+ blockchain1.mine(alice.address)
+
+ transaction = OrderedDict({
+ 'sender_public_key': alice.address,
+ 'recipient_address': bob.address,
+ 'value': 10
+ })
+
+ signature = alice.sign_transaction(transaction)
+ blockchain1.add_transaction(
+ alice.address,
+ bob.address,
+ 10,
+ signature
+ )
+
+ # Save with pending transactions
+ save_blockchain_to_db(blockchain1, db_path)
+
+ # Load and verify
+ blockchain2 = load_blockchain_from_db(db_path)
+ assert len(blockchain2.transactions) > 0
+
+
+class TestMerkleTreeIntegration:
+ """Integration tests for Merkle tree with blockchain."""
+
+ def test_merkle_tree_with_block_transactions(self):
+ """Test Merkle tree creation from block transactions."""
+ blockchain = Blockchain(difficulty=2)
+ wallet = Wallet()
+
+ # Add some transactions and mine
+ for i in range(5):
+ blockchain.transactions.append({
+ 'sender': f'sender_{i}',
+ 'recipient': f'recipient_{i}',
+ 'value': i * 10
+ })
+
+ blockchain.mine(wallet.address)
+
+ # Get the mined block
+ block = blockchain.chain[-1]
+
+ # Create Merkle tree from block transactions
+ merkle_tree = MerkleTree(block.transactions)
+
+ # Verify root hash
+ root_hash = merkle_tree.get_root_hash()
+ assert len(root_hash) == 64 # SHA-256
+
+ # Verify proof for a transaction
+ if block.transactions:
+ tx = block.transactions[0]
+ proof = merkle_tree.get_proof(tx)
+ is_valid = merkle_tree.verify_proof(tx, proof, root_hash)
+ assert is_valid
+
+ def test_merkle_proof_verification_across_blocks(self):
+ """Test Merkle proof verification for transactions across multiple blocks."""
+ blockchain = Blockchain(difficulty=2)
+ wallet = Wallet()
+
+ # Mine several blocks with transactions
+ for block_num in range(3):
+ for tx_num in range(3):
+ blockchain.transactions.append({
+ 'sender': f'sender_{block_num}_{tx_num}',
+ 'recipient': f'recipient_{block_num}_{tx_num}',
+ 'value': (block_num + 1) * (tx_num + 1) * 10
+ })
+
+ blockchain.mine(wallet.address)
+
+ # Verify Merkle proofs for all blocks
+ for block in blockchain.chain[1:]: # Skip genesis
+ if block.transactions:
+ tree = MerkleTree(block.transactions)
+ root = tree.get_root_hash()
+
+ # Verify each transaction
+ for tx in block.transactions:
+ proof = tree.get_proof(tx)
+ assert tree.verify_proof(tx, proof, root)
+
+
+class TestWalletAndTransactions:
+ """Integration tests for wallet and transaction interactions."""
+
+ def test_wallet_export_import_and_use(self):
+ """Test exporting, importing, and using a wallet."""
+ # Create original wallet
+ wallet1 = Wallet()
+ address1 = wallet1.address
+ private_key = wallet1.export_private_key()
+
+ # Import wallet from private key
+ wallet2 = Wallet.from_private_key(private_key)
+ address2 = wallet2.address
+
+ # Verify addresses match
+ assert address1 == address2
+
+ # Create and sign transaction with both wallets
+ transaction = OrderedDict({
+ 'sender_public_key': address1,
+ 'recipient_address': 'recipient',
+ 'value': 100
+ })
+
+ signature1 = wallet1.sign_transaction(transaction)
+ signature2 = wallet2.sign_transaction(transaction)
+
+ # Verify both signatures are valid
+ assert Wallet.verify_signature(address1, signature1, transaction)
+ assert Wallet.verify_signature(address2, signature2, transaction)
+
+ def test_transaction_validation_in_blockchain(self):
+ """Test transaction validation with various scenarios."""
+ blockchain = Blockchain(difficulty=2)
+ alice = Wallet()
+ bob = Wallet()
+
+ # Mine to give Alice funds
+ blockchain.mine(alice.address)
+
+ alice_balance = blockchain.get_balance(alice.address)
+
+ # Valid transaction
+ transaction = OrderedDict({
+ 'sender_public_key': alice.address,
+ 'recipient_address': bob.address,
+ 'value': 10
+ })
+
+ signature = alice.sign_transaction(transaction)
+ assert blockchain.add_transaction(
+ alice.address,
+ bob.address,
+ 10,
+ signature
+ )
+
+ # Invalid signature
+ fake_signature = bob.sign_transaction(transaction)
+ assert not blockchain.add_transaction(
+ alice.address,
+ bob.address,
+ 10,
+ fake_signature
+ )
+
+ # Insufficient balance
+ transaction2 = OrderedDict({
+ 'sender_public_key': alice.address,
+ 'recipient_address': bob.address,
+ 'value': alice_balance + 1000
+ })
+
+ signature2 = alice.sign_transaction(transaction2)
+ assert not blockchain.add_transaction(
+ alice.address,
+ bob.address,
+ alice_balance + 1000,
+ signature2
+ )
+
+
+class TestDatabaseOperations:
+ """Integration tests for database operations."""
+
+ def test_database_queries(self):
+ """Test database query operations."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test.db')
+
+ with BlockchainDB(db_path) as db:
+ # Create test blockchain
+ blockchain = Blockchain(difficulty=2)
+ wallet = Wallet()
+
+ # Mine blocks
+ blockchain.mine(wallet.address)
+ blockchain.mine(wallet.address)
+
+ # Save blocks
+ for block in blockchain.chain:
+ db.save_block(block)
+
+ # Test get_block_by_index
+ block = db.get_block_by_index(0)
+ assert block is not None
+ assert block.index == 0
+
+ # Test get_transactions_by_address
+ transactions = db.get_transactions_by_address(wallet.address)
+ assert len(transactions) > 0
+
+ def test_metadata_storage(self):
+ """Test storing and retrieving metadata."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test.db')
+
+ with BlockchainDB(db_path) as db:
+ # Save metadata
+ db.save_metadata('test_key', 'test_value')
+ db.save_metadata('difficulty', '4')
+
+ # Load metadata
+ value1 = db.load_metadata('test_key')
+ value2 = db.load_metadata('difficulty')
+
+ assert value1 == 'test_value'
+ assert value2 == '4'
+
+ # Non-existent key
+ value3 = db.load_metadata('nonexistent')
+ assert value3 is None
+
+
+@pytest.mark.integration
+class TestCompleteSystem:
+ """Tests for the complete blockchain system."""
+
+ @pytest.mark.slow
+ def test_complete_blockchain_lifecycle(self):
+ """Test complete blockchain lifecycle."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'blockchain.db')
+
+ # Phase 1: Create and populate blockchain
+ blockchain = Blockchain(difficulty=2)
+ wallets = [Wallet() for _ in range(3)]
+
+ # Mine initial blocks
+ for _ in range(2):
+ blockchain.mine(wallets[0].address)
+
+ # Create transactions
+ transaction = OrderedDict({
+ 'sender_public_key': wallets[0].address,
+ 'recipient_address': wallets[1].address,
+ 'value': 20
+ })
+
+ signature = wallets[0].sign_transaction(transaction)
+ blockchain.add_transaction(
+ wallets[0].address,
+ wallets[1].address,
+ 20,
+ signature
+ )
+
+ # Mine transaction
+ blockchain.mine(wallets[2].address)
+
+ # Verify initial state
+ assert blockchain.is_valid_chain()
+ initial_length = blockchain.get_chain_length()
+ initial_balance_0 = blockchain.get_balance(wallets[0].address)
+ initial_balance_1 = blockchain.get_balance(wallets[1].address)
+
+ # Phase 2: Save to database
+ assert save_blockchain_to_db(blockchain, db_path)
+
+ # Phase 3: Load from database
+ loaded_blockchain = load_blockchain_from_db(db_path)
+ assert loaded_blockchain is not None
+
+ # Phase 4: Verify loaded blockchain
+ assert loaded_blockchain.get_chain_length() == initial_length
+ assert loaded_blockchain.is_valid_chain()
+
+ # Verify balances are preserved
+ loaded_balance_0 = loaded_blockchain.get_balance(wallets[0].address)
+ loaded_balance_1 = loaded_blockchain.get_balance(wallets[1].address)
+
+ assert loaded_balance_0 == initial_balance_0
+ assert loaded_balance_1 == initial_balance_1
+
+ # Phase 5: Continue using loaded blockchain
+ loaded_blockchain.mine(wallets[2].address)
+ assert loaded_blockchain.get_chain_length() == initial_length + 1
+ assert loaded_blockchain.is_valid_chain()
+
+
+if __name__ == "__main__":
+ # Run integration tests
+ pytest.main([__file__, '-v'])
diff --git a/tests/test_merkle_tree.py b/tests/test_merkle_tree.py
new file mode 100644
index 0000000..64bc522
--- /dev/null
+++ b/tests/test_merkle_tree.py
@@ -0,0 +1,73 @@
+"""
+Test for Merkle tree implementation.
+"""
+
+import pytest
+from blockchain_core.merkle_tree import MerkleTree, MerkleNode
+
+
+class TestMerkleTree:
+ """Test cases for Merkle tree."""
+
+ def test_merkle_tree_creation(self):
+ """Test creating a Merkle tree."""
+ transactions = [
+ {'sender': 'Alice', 'recipient': 'Bob', 'value': 10},
+ {'sender': 'Bob', 'recipient': 'Charlie', 'value': 20}
+ ]
+
+ tree = MerkleTree(transactions)
+ assert tree is not None
+ assert tree.root is not None
+
+ def test_merkle_root_hash(self):
+ """Test Merkle root hash generation."""
+ transactions = [
+ {'sender': 'Alice', 'recipient': 'Bob', 'value': 10}
+ ]
+
+ tree = MerkleTree(transactions)
+ root_hash = tree.get_root_hash()
+
+ assert root_hash is not None
+ assert len(root_hash) == 64 # SHA-256
+
+ def test_merkle_proof(self):
+ """Test Merkle proof generation and verification."""
+ transactions = [
+ {'sender': f'sender_{i}', 'recipient': f'recipient_{i}', 'value': i}
+ for i in range(4)
+ ]
+
+ tree = MerkleTree(transactions)
+ root_hash = tree.get_root_hash()
+
+ # Generate proof for first transaction
+ proof = tree.get_proof(transactions[0])
+ assert proof is not None
+
+ # Verify proof
+ is_valid = tree.verify_proof(transactions[0], proof, root_hash)
+ assert is_valid is True
+
+ def test_empty_merkle_tree(self):
+ """Test empty Merkle tree."""
+ tree = MerkleTree([])
+ assert tree.root is not None
+ assert tree.get_root_hash() is not None
+
+ def test_merkle_tree_height(self):
+ """Test Merkle tree height calculation."""
+ transactions = [{'tx': i} for i in range(8)]
+ tree = MerkleTree(transactions)
+
+ height = tree.get_tree_height()
+ assert height > 0
+
+ def test_merkle_tree_size(self):
+ """Test Merkle tree size calculation."""
+ transactions = [{'tx': i} for i in range(4)]
+ tree = MerkleTree(transactions)
+
+ size = tree.get_tree_size()
+ assert size > 0
diff --git a/tests/test_persistence.py b/tests/test_persistence.py
new file mode 100644
index 0000000..3966d9b
--- /dev/null
+++ b/tests/test_persistence.py
@@ -0,0 +1,51 @@
+"""
+Test for blockchain persistence.
+"""
+
+import pytest
+import tempfile
+import os
+from blockchain_core.persistence import BlockchainDB
+
+
+class TestBlockchainDB:
+ """Test cases for blockchain database."""
+
+ def test_database_initialization(self):
+ """Test database initialization."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test.db')
+ db = BlockchainDB(db_path)
+ assert db is not None
+ assert db.conn is not None
+ db.close()
+
+ def test_metadata_operations(self):
+ """Test metadata save and load."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test.db')
+ with BlockchainDB(db_path) as db:
+ # Save metadata
+ success = db.save_metadata('test_key', 'test_value')
+ assert success is True
+
+ # Load metadata
+ value = db.load_metadata('test_key')
+ assert value == 'test_value'
+
+ # Non-existent key
+ value = db.load_metadata('nonexistent')
+ assert value is None
+
+ def test_context_manager(self):
+ """Test context manager usage."""
+ with tempfile.TemporaryDirectory() as tmpdir:
+ db_path = os.path.join(tmpdir, 'test.db')
+ with BlockchainDB(db_path) as db:
+ db.save_metadata('key', 'value')
+
+ # Database should be closed
+ # Re-open to verify data persisted
+ with BlockchainDB(db_path) as db:
+ value = db.load_metadata('key')
+ assert value == 'value'
diff --git a/tests/test_transaction.py b/tests/test_transaction.py
new file mode 100644
index 0000000..be785d4
--- /dev/null
+++ b/tests/test_transaction.py
@@ -0,0 +1,113 @@
+"""
+Unit tests for the Transaction class.
+"""
+
+import pytest
+from collections import OrderedDict
+from blockchain_core.transaction import Transaction
+from blockchain_core.wallet import Wallet
+
+
+class TestTransaction:
+ """Test cases for Transaction class."""
+
+ def test_transaction_creation(self):
+ """Test creating a new transaction."""
+ sender_key = "sender_public_key"
+ recipient = "recipient_address"
+ value = 50
+
+ transaction = Transaction(sender_key, recipient, value)
+
+ assert transaction.sender_public_key == sender_key
+ assert transaction.recipient_address == recipient
+ assert transaction.value == value
+ assert transaction.signature is None
+
+ def test_to_dict(self):
+ """Test converting transaction to dictionary."""
+ transaction = Transaction("sender", "recipient", 100)
+ tx_dict = transaction.to_dict()
+
+ assert isinstance(tx_dict, OrderedDict)
+ assert tx_dict['sender_public_key'] == "sender"
+ assert tx_dict['recipient_address'] == "recipient"
+ assert tx_dict['value'] == 100
+
+ def test_sign_transaction(self):
+ """Test signing a transaction."""
+ wallet = Wallet()
+ transaction = Transaction(wallet.address, "recipient", 25)
+
+ transaction.sign(wallet)
+
+ assert transaction.signature is not None
+ assert isinstance(transaction.signature, bytes)
+
+ def test_sign_wrong_wallet(self):
+ """Test signing with wrong wallet raises error."""
+ wallet1 = Wallet()
+ wallet2 = Wallet()
+
+ transaction = Transaction(wallet1.address, "recipient", 25)
+
+ with pytest.raises(ValueError):
+ transaction.sign(wallet2)
+
+ def test_is_valid(self):
+ """Test transaction validation."""
+ wallet = Wallet()
+ transaction = Transaction(wallet.address, "recipient", 25)
+
+ # Unsigned transaction is invalid
+ assert transaction.is_valid() is False
+
+ # Signed transaction is valid
+ transaction.sign(wallet)
+ assert transaction.is_valid() is True
+
+ def test_tampered_transaction(self):
+ """Test detection of tampered transactions."""
+ wallet = Wallet()
+ transaction = Transaction(wallet.address, "recipient", 25)
+ transaction.sign(wallet)
+
+ # Tamper with value
+ transaction.value = 1000
+
+ assert transaction.is_valid() is False
+
+ def test_create_coinbase(self):
+ """Test creating a coinbase transaction."""
+ recipient = "miner_address"
+ reward = 50
+
+ coinbase = Transaction.create_coinbase(recipient, reward)
+
+ assert coinbase['sender_public_key'] == 'network'
+ assert coinbase['recipient_address'] == recipient
+ assert coinbase['value'] == reward
+
+ def test_from_dict(self):
+ """Test creating transaction from dictionary."""
+ data = {
+ 'sender_public_key': 'sender',
+ 'recipient_address': 'recipient',
+ 'value': 75,
+ 'signature': b'test_signature'
+ }
+
+ transaction = Transaction.from_dict(data)
+
+ assert transaction.sender_public_key == 'sender'
+ assert transaction.recipient_address == 'recipient'
+ assert transaction.value == 75
+ assert transaction.signature == b'test_signature'
+
+ def test_repr(self):
+ """Test string representation."""
+ transaction = Transaction("sender_key", "recipient_addr", 100)
+ repr_str = repr(transaction)
+
+ assert 'Transaction' in repr_str
+ assert 'value=100' in repr_str
diff --git a/tests/test_utils.py b/tests/test_utils.py
new file mode 100644
index 0000000..f6c8c4b
--- /dev/null
+++ b/tests/test_utils.py
@@ -0,0 +1,114 @@
+"""
+Unit tests for utility functions.
+"""
+
+import pytest
+from blockchain_core.utils import (
+ compute_hash,
+ validate_address,
+ serialize_transaction,
+ validate_transaction_structure
+)
+
+
+class TestUtils:
+ """Test cases for utility functions."""
+
+ def test_compute_hash_string(self):
+ """Test hashing a string."""
+ data = "test data"
+ hash1 = compute_hash(data)
+ hash2 = compute_hash(data)
+
+ assert hash1 == hash2
+ assert len(hash1) == 64 # SHA-256
+ assert isinstance(hash1, str)
+
+ def test_compute_hash_dict(self):
+ """Test hashing a dictionary."""
+ data = {'key': 'value', 'number': 42}
+ hash1 = compute_hash(data)
+
+ assert len(hash1) == 64
+ assert isinstance(hash1, str)
+
+ def test_compute_hash_consistency(self):
+ """Test that same data produces same hash."""
+ data = {'a': 1, 'b': 2}
+ hash1 = compute_hash(data)
+ hash2 = compute_hash(data)
+
+ assert hash1 == hash2
+
+ def test_compute_hash_different_data(self):
+ """Test that different data produces different hashes."""
+ hash1 = compute_hash({'a': 1})
+ hash2 = compute_hash({'a': 2})
+
+ assert hash1 != hash2
+
+ def test_validate_address_valid(self):
+ """Test validating a valid address."""
+ valid_address = "-----BEGIN PUBLIC KEY-----\nMFYwEAYHK"
+ assert validate_address(valid_address) is True
+
+ def test_validate_address_invalid(self):
+ """Test validating invalid addresses."""
+ assert validate_address("") is False
+ assert validate_address(None) is False
+ assert validate_address("not a valid address") is False
+ assert validate_address(123) is False
+
+ def test_serialize_transaction(self):
+ """Test transaction serialization."""
+ transaction = {
+ 'sender': 'Alice',
+ 'recipient': 'Bob',
+ 'value': 100
+ }
+
+ serialized = serialize_transaction(transaction)
+
+ assert isinstance(serialized, str)
+ assert 'Alice' in serialized
+ assert 'Bob' in serialized
+ assert '100' in serialized
+
+ def test_serialize_transaction_consistency(self):
+ """Test that serialization is consistent."""
+ transaction = {'b': 2, 'a': 1} # Unordered
+
+ result1 = serialize_transaction(transaction)
+ result2 = serialize_transaction(transaction)
+
+ assert result1 == result2
+
+ def test_validate_transaction_structure_valid(self):
+ """Test validating a valid transaction structure."""
+ transaction = {
+ 'sender_public_key': 'sender',
+ 'recipient_address': 'recipient',
+ 'value': 50
+ }
+
+ assert validate_transaction_structure(transaction) is True
+
+ def test_validate_transaction_structure_missing_fields(self):
+ """Test validating incomplete transactions."""
+ # Missing value
+ transaction1 = {
+ 'sender_public_key': 'sender',
+ 'recipient_address': 'recipient'
+ }
+ assert validate_transaction_structure(transaction1) is False
+
+ # Missing sender
+ transaction2 = {
+ 'recipient_address': 'recipient',
+ 'value': 50
+ }
+ assert validate_transaction_structure(transaction2) is False
+
+ # Empty transaction
+ transaction3 = {}
+ assert validate_transaction_structure(transaction3) is False
diff --git a/tests/test_wallet.py b/tests/test_wallet.py
new file mode 100644
index 0000000..7a4d937
--- /dev/null
+++ b/tests/test_wallet.py
@@ -0,0 +1,126 @@
+"""
+Unit tests for the Wallet class.
+"""
+
+import pytest
+from collections import OrderedDict
+from blockchain_core.wallet import Wallet
+
+
+class TestWallet:
+ """Test cases for Wallet class."""
+
+ def test_wallet_creation(self):
+ """Test creating a new wallet."""
+ wallet = Wallet()
+
+ assert wallet.private_key is not None
+ assert wallet.public_key is not None
+ assert wallet.address is not None
+ assert isinstance(wallet.address, str)
+
+ def test_unique_wallets(self):
+ """Test that different wallets have different keys."""
+ wallet1 = Wallet()
+ wallet2 = Wallet()
+
+ assert wallet1.address != wallet2.address
+ assert wallet1.private_key != wallet2.private_key
+
+ def test_serialize_public_key(self):
+ """Test public key serialization."""
+ wallet = Wallet()
+ serialized = wallet.serialize_public_key()
+
+ assert serialized.startswith('-----BEGIN PUBLIC KEY-----')
+ assert serialized.endswith('-----END PUBLIC KEY-----\n')
+
+ def test_sign_transaction(self):
+ """Test transaction signing."""
+ wallet = Wallet()
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient_address',
+ 'value': 10
+ })
+
+ signature = wallet.sign_transaction(transaction)
+
+ assert signature is not None
+ assert isinstance(signature, bytes)
+ assert len(signature) > 0
+
+ def test_verify_signature(self):
+ """Test signature verification."""
+ wallet = Wallet()
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient_address',
+ 'value': 10
+ })
+
+ signature = wallet.sign_transaction(transaction)
+ is_valid = Wallet.verify_signature(wallet.address, signature, transaction)
+
+ assert is_valid is True
+
+ def test_verify_invalid_signature(self):
+ """Test invalid signature detection."""
+ wallet1 = Wallet()
+ wallet2 = Wallet()
+
+ transaction = OrderedDict({
+ 'sender_public_key': wallet1.address,
+ 'recipient_address': 'recipient_address',
+ 'value': 10
+ })
+
+ signature = wallet1.sign_transaction(transaction)
+
+ # Try to verify with wrong public key
+ is_valid = Wallet.verify_signature(wallet2.address, signature, transaction)
+
+ assert is_valid is False
+
+ def test_verify_tampered_transaction(self):
+ """Test detection of tampered transactions."""
+ wallet = Wallet()
+ transaction = OrderedDict({
+ 'sender_public_key': wallet.address,
+ 'recipient_address': 'recipient_address',
+ 'value': 10
+ })
+
+ signature = wallet.sign_transaction(transaction)
+
+ # Tamper with transaction
+ transaction['value'] = 1000
+
+ is_valid = Wallet.verify_signature(wallet.address, signature, transaction)
+
+ assert is_valid is False
+
+ def test_export_private_key(self):
+ """Test private key export."""
+ wallet = Wallet()
+ private_key_pem = wallet.export_private_key()
+
+ assert private_key_pem.startswith('-----BEGIN PRIVATE KEY-----')
+ assert private_key_pem.endswith('-----END PRIVATE KEY-----\n')
+
+ def test_from_private_key(self):
+ """Test wallet import from private key."""
+ wallet1 = Wallet()
+ private_key_pem = wallet1.export_private_key()
+
+ wallet2 = Wallet.from_private_key(private_key_pem)
+
+ assert wallet1.address == wallet2.address
+
+ def test_repr(self):
+ """Test string representation."""
+ wallet = Wallet()
+ repr_str = repr(wallet)
+
+ assert 'Wallet' in repr_str
+ assert 'address=' in repr_str