From 0e9cf9dd9be95d83a68de789759cd6f1af17f468 Mon Sep 17 00:00:00 2001 From: Pedro Perafan Date: Sun, 9 Nov 2025 23:49:05 -0600 Subject: [PATCH] docs: Comprehensive v2 documentation update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Complete documentation overhaul for ChainForge v2 covering all new features and providing comprehensive guides for users, contributors, and deployers. New Documentation Files: - CHANGELOG.md: Complete version history (v1.0.0 → v2.0.0) - CONTRIBUTING.md: Contribution guidelines and workflow - SECURITY.md: Security policies and best practices - API_DOCUMENTATION.md: Complete API reference with examples - DEPLOYMENT.md: Production deployment guide Updated Documentation: - README.md: Complete rewrite with v2 features * Proof of Work mining explanation (advanced level) * Comparison with Bitcoin PoW * API versioning (/api/v1) * Rate limiting documentation * Input validation details * Environment configuration guide * CI/CD pipeline documentation * Security section with known limitations * Performance impact tables - CLAUDE.md: Complete rewrite for Claude Code * All v2 dependencies and tools * Proof of Work implementation details * Rate limiting and validation architecture * Testing strategy and guidelines * CI/CD pipeline documentation * Common development tasks * Troubleshooting section * Educational objectives Documentation Features: ✅ 7 markdown files (~76KB total) ✅ Advanced PoW explanation with Bitcoin comparison ✅ Complete API reference with curl/Ruby/Python/JS examples ✅ Production deployment guide (nginx, SSL, MongoDB, systemd) ✅ Security best practices and known limitations ✅ Contribution workflow and code quality guidelines ✅ Version history following Keep a Changelog format ✅ All v2 PRs documented (#1-7) All tests passing (17 examples, 0 failures) RuboCop clean (10 files, no offenses) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- API_DOCUMENTATION.md | 568 +++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 144 +++++++++++ CLAUDE.md | 448 +++++++++++++++++++++++++++++++--- CONTRIBUTING.md | 290 ++++++++++++++++++++++ DEPLOYMENT.md | 559 ++++++++++++++++++++++++++++++++++++++++++ README.md | 429 +++++++++++++++++++++++++++++--- SECURITY.md | 315 ++++++++++++++++++++++++ 7 files changed, 2684 insertions(+), 69 deletions(-) create mode 100644 API_DOCUMENTATION.md create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 DEPLOYMENT.md create mode 100644 SECURITY.md diff --git a/API_DOCUMENTATION.md b/API_DOCUMENTATION.md new file mode 100644 index 0000000..55de9d7 --- /dev/null +++ b/API_DOCUMENTATION.md @@ -0,0 +1,568 @@ +# ChainForge API Documentation + +Complete API reference for ChainForge v2.0. + +## Base URL + +``` +http://localhost:1910/api/v1 +``` + +## Authentication + +None required (educational project). + +## Rate Limiting + +All endpoints are rate-limited per IP address: + +| Endpoint | Limit | Window | +|----------|-------|--------| +| All | 60 requests | 60 seconds | +| POST /chain | 10 requests | 60 seconds | +| POST /chain/:id/block | 30 requests | 60 seconds | + +**Rate Limit Response (429):** +```json +{ + "error": "Rate limit exceeded. Please try again later." +} +``` + +## Content Type + +All requests and responses use `application/json`. + +## Error Handling + +### HTTP Status Codes + +- `200` - Success +- `400` - Validation Error +- `404` - Not Found +- `429` - Rate Limit Exceeded +- `500` - Server Error + +### Error Response Format + +**Validation Error (400):** +```json +{ + "errors": { + "field_name": ["error message 1", "error message 2"] + } +} +``` + +**Rate Limit (429):** +```json +{ + "error": "Rate limit exceeded. Please try again later." +} +``` + +**Server Error (500):** +```json +{ + "error": "Error message" +} +``` + +--- + +## Endpoints + +### 1. Create Blockchain + +Creates a new blockchain instance with genesis block. + +**Endpoint:** `POST /api/v1/chain` + +**Rate Limit:** 10 requests/minute per IP + +**Request:** +```bash +curl -X POST http://localhost:1910/api/v1/chain +``` + +**Response (200):** +```json +{ + "id": "507f1f77bcf86cd799439011" +} +``` + +**Response Fields:** +- `id` (string): Unique blockchain identifier (MongoDB ObjectId) + +**Example:** +```bash +# Create blockchain +curl -X POST http://localhost:1910/api/v1/chain + +# Response +{"id":"674f8a2b1c3d4e5f6a7b8c9d"} +``` + +--- + +### 2. Add Block (Mine) + +Mines and adds a new block to the blockchain using Proof of Work. + +**Endpoint:** `POST /api/v1/chain/:id/block` + +**Rate Limit:** 30 requests/minute per IP + +**Request Parameters:** + +| Parameter | Type | Required | Validation | Default | +|-----------|------|----------|------------|---------| +| `data` | string | Yes | Non-empty | - | +| `difficulty` | integer | No | 1-10 | `DEFAULT_DIFFICULTY` env var (2) | + +**Request:** +```bash +curl -X POST http://localhost:1910/api/v1/chain/507f1f77bcf86cd799439011/block \ + -H 'Content-Type: application/json' \ + -d '{"data": "Transaction data", "difficulty": 3}' +``` + +**Response (200):** +```json +{ + "chain_id": "507f1f77bcf86cd799439011", + "block_id": "507f191e810c19729de860ea", + "block_hash": "000a1b2c3d4e5f6789abcdef", + "nonce": 1542, + "difficulty": 3 +} +``` + +**Response Fields:** +- `chain_id` (string): Blockchain identifier +- `block_id` (string): New block identifier +- `block_hash` (string): Mined block hash (starts with N zeros) +- `nonce` (integer): Number of mining iterations +- `difficulty` (integer): Difficulty level used + +**Validation Errors (400):** +```json +{ + "errors": { + "data": ["must be filled"], + "difficulty": ["must be between 1 and 10"] + } +} +``` + +**Mining Time:** +- Difficulty 1-2: < 1 second +- Difficulty 3-4: Few seconds +- Difficulty 5-6: Minutes +- Difficulty 7+: Hours or more + +**Example:** +```bash +# Mine block with default difficulty +curl -X POST http://localhost:1910/api/v1/chain/674f8a2b1c3d4e5f6a7b8c9d/block \ + -H 'Content-Type: application/json' \ + -d '{"data": "Hello World"}' + +# Response +{ + "chain_id": "674f8a2b1c3d4e5f6a7b8c9d", + "block_id": "674f8b3c2d4e5f6g7h8i9j0k", + "block_hash": "00a1b2c3d4e5f6789...", + "nonce": 157, + "difficulty": 2 +} +``` + +--- + +### 3. Get Block Details + +Retrieves complete block information including mining data. + +**Endpoint:** `GET /api/v1/chain/:id/block/:block_id` + +**Rate Limit:** 60 requests/minute (global) + +**Request:** +```bash +curl http://localhost:1910/api/v1/chain/507f1f77bcf86cd799439011/block/507f191e810c19729de860ea +``` + +**Response (200):** +```json +{ + "chain_id": "507f1f77bcf86cd799439011", + "block": { + "id": "507f191e810c19729de860ea", + "index": 1, + "data": "Transaction data", + "hash": "000a1b2c3d4e5f6789abcdef", + "previous_hash": "00f8a2b1c3d4e5f67", + "nonce": 1542, + "difficulty": 3, + "timestamp": 1699564821, + "valid_hash": true + } +} +``` + +**Response Fields:** +- `chain_id` (string): Blockchain identifier +- `block.id` (string): Block identifier +- `block.index` (integer): Block position in chain (starts at 0) +- `block.data` (string): Stored data +- `block.hash` (string): Block's SHA256 hash +- `block.previous_hash` (string): Previous block's hash +- `block.nonce` (integer): Mining nonce value +- `block.difficulty` (integer): Difficulty level used +- `block.timestamp` (integer): Unix timestamp +- `block.valid_hash` (boolean): Whether hash meets difficulty requirement + +**Error (404):** +```json +{ + "error": "Block not found" +} +``` + +**Example:** +```bash +# Get block details +curl http://localhost:1910/api/v1/chain/674f8a2b1c3d4e5f6a7b8c9d/block/674f8b3c2d4e5f6g7h8i9j0k + +# Response includes full mining info +{ + "chain_id": "674f8a2b1c3d4e5f6a7b8c9d", + "block": { + "id": "674f8b3c2d4e5f6g7h8i9j0k", + "index": 1, + "data": "Hello World", + "hash": "00a1b2c3d4e5f6789...", + "previous_hash": "0f9e8d7c6b5a4...", + "nonce": 157, + "difficulty": 2, + "timestamp": 1731729600, + "valid_hash": true + } +} +``` + +--- + +### 4. Validate Block Data + +Validates if provided data matches the block's stored hash. + +**Endpoint:** `POST /api/v1/chain/:id/block/:block_id/valid` + +**Rate Limit:** 60 requests/minute (global) + +**Request Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `data` | string | Yes | Data to validate | + +**Request:** +```bash +curl -X POST http://localhost:1910/api/v1/chain/507f1f77bcf86cd799439011/block/507f191e810c19729de860ea/valid \ + -H 'Content-Type: application/json' \ + -d '{"data": "Transaction data"}' +``` + +**Response (200):** +```json +{ + "chain_id": "507f1f77bcf86cd799439011", + "block_id": "507f191e810c19729de860ea", + "valid": true +} +``` + +**Response Fields:** +- `chain_id` (string): Blockchain identifier +- `block_id` (string): Block identifier +- `valid` (boolean): Whether data matches block's hash + +**Validation Errors (400):** +```json +{ + "errors": { + "data": ["must be filled"] + } +} +``` + +**Example:** +```bash +# Validate correct data +curl -X POST http://localhost:1910/api/v1/chain/674f8a2b1c3d4e5f6a7b8c9d/block/674f8b3c2d4e5f6g7h8i9j0k/valid \ + -H 'Content-Type: application/json' \ + -d '{"data": "Hello World"}' + +# Response +{"chain_id":"674f8a2b1c3d4e5f6a7b8c9d","block_id":"674f8b3c2d4e5f6g7h8i9j0k","valid":true} + +# Validate incorrect data +curl -X POST http://localhost:1910/api/v1/chain/674f8a2b1c3d4e5f6a7b8c9d/block/674f8b3c2d4e5f6g7h8i9j0k/valid \ + -H 'Content-Type: application/json' \ + -d '{"data": "Wrong Data"}' + +# Response +{"chain_id":"674f8a2b1c3d4e5f6a7b8c9d","block_id":"674f8b3c2d4e5f6g7h8i9j0k","valid":false} +``` + +--- + +## Common Workflows + +### Create and Mine Blocks + +```bash +# 1. Create blockchain +CHAIN_ID=$(curl -s -X POST http://localhost:1910/api/v1/chain | jq -r '.id') + +# 2. Mine first block (difficulty 2) +BLOCK1=$(curl -s -X POST http://localhost:1910/api/v1/chain/$CHAIN_ID/block \ + -H 'Content-Type: application/json' \ + -d '{"data": "First block"}') + +# 3. Mine second block (difficulty 3) +BLOCK2=$(curl -s -X POST http://localhost:1910/api/v1/chain/$CHAIN_ID/block \ + -H 'Content-Type: application/json' \ + -d '{"data": "Second block", "difficulty": 3}') + +# 4. Get block details +curl http://localhost:1910/api/v1/chain/$CHAIN_ID/block/$(echo $BLOCK1 | jq -r '.block_id') + +# 5. Validate block data +curl -X POST http://localhost:1910/api/v1/chain/$CHAIN_ID/block/$(echo $BLOCK1 | jq -r '.block_id')/valid \ + -H 'Content-Type: application/json' \ + -d '{"data": "First block"}' +``` + +### Handle Rate Limiting + +```bash +# Check rate limit headers (if implemented) +curl -i http://localhost:1910/api/v1/chain + +# Wait and retry on 429 +while true; do + response=$(curl -s -w "%{http_code}" -X POST http://localhost:1910/api/v1/chain) + code=${response: -3} + if [ "$code" = "429" ]; then + echo "Rate limited, waiting 60 seconds..." + sleep 60 + else + break + fi +done +``` + +### Handle Validation Errors + +```bash +# Validate input before sending +data="my data" +difficulty=5 + +if [ -z "$data" ]; then + echo "Error: data cannot be empty" + exit 1 +fi + +if [ "$difficulty" -lt 1 ] || [ "$difficulty" -gt 10 ]; then + echo "Error: difficulty must be between 1-10" + exit 1 +fi + +# Send request +curl -X POST http://localhost:1910/api/v1/chain/$CHAIN_ID/block \ + -H 'Content-Type: application/json' \ + -d "{\"data\": \"$data\", \"difficulty\": $difficulty}" +``` + +--- + +## Client Libraries + +### Ruby Client Example + +```ruby +require 'httparty' + +class ChainForgeClient + BASE_URL = 'http://localhost:1910/api/v1' + + def create_chain + response = HTTParty.post("#{BASE_URL}/chain") + JSON.parse(response.body) + end + + def mine_block(chain_id, data, difficulty = nil) + body = { data: data } + body[:difficulty] = difficulty if difficulty + + response = HTTParty.post( + "#{BASE_URL}/chain/#{chain_id}/block", + body: body.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + + JSON.parse(response.body) + end + + def get_block(chain_id, block_id) + response = HTTParty.get("#{BASE_URL}/chain/#{chain_id}/block/#{block_id}") + JSON.parse(response.body) + end + + def validate_block(chain_id, block_id, data) + response = HTTParty.post( + "#{BASE_URL}/chain/#{chain_id}/block/#{block_id}/valid", + body: { data: data }.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + + JSON.parse(response.body) + end +end + +# Usage +client = ChainForgeClient.new +chain = client.create_chain +block = client.mine_block(chain['id'], 'Hello World', 2) +details = client.get_block(chain['id'], block['block_id']) +validation = client.validate_block(chain['id'], block['block_id'], 'Hello World') +``` + +### Python Client Example + +```python +import requests + +class ChainForgeClient: + BASE_URL = 'http://localhost:1910/api/v1' + + def create_chain(self): + response = requests.post(f'{self.BASE_URL}/chain') + return response.json() + + def mine_block(self, chain_id, data, difficulty=None): + payload = {'data': data} + if difficulty: + payload['difficulty'] = difficulty + + response = requests.post( + f'{self.BASE_URL}/chain/{chain_id}/block', + json=payload + ) + return response.json() + + def get_block(self, chain_id, block_id): + response = requests.get( + f'{self.BASE_URL}/chain/{chain_id}/block/{block_id}' + ) + return response.json() + + def validate_block(self, chain_id, block_id, data): + response = requests.post( + f'{self.BASE_URL}/chain/{chain_id}/block/{block_id}/valid', + json={'data': data} + ) + return response.json() + +# Usage +client = ChainForgeClient() +chain = client.create_chain() +block = client.mine_block(chain['id'], 'Hello World', difficulty=2) +details = client.get_block(chain['id'], block['block_id']) +validation = client.validate_block(chain['id'], block['block_id'], 'Hello World') +``` + +### JavaScript Client Example + +```javascript +class ChainForgeClient { + constructor(baseUrl = 'http://localhost:1910/api/v1') { + this.baseUrl = baseUrl; + } + + async createChain() { + const response = await fetch(`${this.baseUrl}/chain`, { + method: 'POST' + }); + return response.json(); + } + + async mineBlock(chainId, data, difficulty = null) { + const payload = { data }; + if (difficulty) payload.difficulty = difficulty; + + const response = await fetch(`${this.baseUrl}/chain/${chainId}/block`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload) + }); + return response.json(); + } + + async getBlock(chainId, blockId) { + const response = await fetch( + `${this.baseUrl}/chain/${chainId}/block/${blockId}` + ); + return response.json(); + } + + async validateBlock(chainId, blockId, data) { + const response = await fetch( + `${this.baseUrl}/chain/${chainId}/block/${blockId}/valid`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ data }) + } + ); + return response.json(); + } +} + +// Usage +(async () => { + const client = new ChainForgeClient(); + const chain = await client.createChain(); + const block = await client.mineBlock(chain.id, 'Hello World', 2); + const details = await client.getBlock(chain.id, block.block_id); + const validation = await client.validateBlock(chain.id, block.block_id, 'Hello World'); +})(); +``` + +--- + +## Versioning + +Current API version: **v1** + +**URL Pattern:** `/api/v1/*` + +Future versions will use `/api/v2/*`, `/api/v3/*`, etc. + +--- + +## Changelog + +See [CHANGELOG.md](CHANGELOG.md) for API changes. + +--- + +## Support + +- GitHub Issues: https://github.com/Perafan18/chain_forge/issues +- Documentation: See README.md, CLAUDE.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..628a4ac --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,144 @@ +# Changelog + +All notable changes to ChainForge 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] + +### Planned +- Block explorer web interface +- Dynamic difficulty adjustment +- Advanced metrics and monitoring + +## [2.0.0] - 2025-11-09 + +### Added + +#### Proof of Work (PR #4) +- **Mining Algorithm**: Implemented PoW consensus mechanism + - `nonce` field for mining iterations + - `difficulty` field (1-10) for hash target configuration + - `mine_block` method implements incremental nonce search + - `valid_hash?` method verifies PoW compliance +- **API Support**: Optional `difficulty` parameter in block creation endpoint +- **Performance**: Mining time scales with difficulty (1-2: instant, 5+: minutes) + +#### API Versioning (PR #5) +- **Namespace**: All endpoints moved to `/api/v1` +- **New Endpoint**: `GET /api/v1/chain/:id/block/:block_id` retrieves block details +- **Future-proof**: Enables API evolution without breaking changes +- **Responses**: Include PoW fields (nonce, difficulty, valid_hash) + +#### API Security (PR #6) +- **Rate Limiting**: Rack::Attack middleware protection + - Global: 60 requests/minute per IP + - Chain creation: 10 requests/minute per IP + - Block creation: 30 requests/minute per IP + - Returns 429 status when exceeded +- **Input Validation**: dry-validation with detailed error messages + - `data` field must be non-empty string + - `difficulty` must be integer between 1-10 + - Returns 400 status with structured errors + +#### Environment Configuration (PR #7) +- **Template**: `.env.example` file for easy setup +- **DEFAULT_DIFFICULTY**: Configurable mining difficulty via environment variable +- **Security**: Removed `.env` from git tracking +- **Documentation**: Environment variable reference in README + +#### Testing Infrastructure (PR #2) +- **RuboCop**: Style enforcement with rubocop-rspec plugin +- **SimpleCov**: Test coverage reporting (>90% coverage) +- **Configuration**: `.rubocop.yml` with project-specific rules +- **Test Database**: Separate `chain_forge_test` database + +#### CI/CD Pipeline (PR #3) +- **GitHub Actions**: Automated testing on every push and PR +- **Checks**: RuboCop linting + RSpec test suite +- **MongoDB**: Service container for integration tests +- **Quality Gates**: PRs cannot merge without passing CI + +#### Documentation (PR #1 & #8) +- **README**: Complete v2 feature documentation with PoW explanation +- **CLAUDE.md**: Claude Code guidance with v2 architecture +- **CHANGELOG.md**: This file, version history tracking +- **CONTRIBUTING.md**: Contribution guidelines and workflow +- **SECURITY.md**: Security policies and best practices +- **API_DOCUMENTATION.md**: Complete API reference with examples +- **DEPLOYMENT.md**: Production deployment guide + +### Changed +- **Block Hash**: Now includes nonce in hash calculation +- **Chain Validation**: Added PoW verification (`valid_hash?` check) +- **Block Creation**: Mining process adds computational delay +- **API Responses**: Include mining information (nonce, difficulty, valid_hash) +- **Genesis Blocks**: Use DEFAULT_DIFFICULTY from environment + +### Breaking Changes +- **API Namespace**: All endpoints moved from `/` to `/api/v1/` + - Old: `POST /chain` + - New: `POST /api/v1/chain` +- **Mining Delay**: Block creation now requires PoW mining (may take seconds/minutes) +- **Response Format**: Block responses include new fields (nonce, difficulty, valid_hash) +- **Environment**: DEFAULT_DIFFICULTY must be configured (defaults to 2) + +### Migration Guide +1. Update all API calls to use `/api/v1` prefix +2. Copy `.env.example` to `.env` and configure DEFAULT_DIFFICULTY +3. Update client code to handle new response fields (nonce, difficulty) +4. Expect longer block creation times due to mining +5. Handle new error responses (400 validation, 429 rate limit) + +## [1.0.0] - 2025-11-08 + +### Added +- **Blockchain Implementation**: Core blockchain data structure +- **Block Model**: SHA256 hashing with chain linking +- **REST API**: Sinatra-based HTTP API + - `POST /chain` - Create blockchain + - `POST /chain/:id/block` - Add block + - `POST /chain/:id/block/:block_id/valid` - Validate block +- **MongoDB Persistence**: Mongoid ODM integration +- **Chain Validation**: Integrity checking via hash verification +- **Genesis Block**: Auto-generation on blockchain creation +- **Docker Support**: docker-compose configuration +- **Testing**: RSpec test suite +- **Documentation**: Basic README with setup instructions + +### Core Features +- Cryptographic hashing (SHA256) +- Immutable chain structure +- Hash-based tamper detection +- RESTful API design +- MongoDB document storage + +## Release Notes + +### v2.0.0 - Major Update +This release transforms ChainForge from a basic blockchain implementation to a professional-grade educational project. Key highlights: + +**🔨 Proof of Work**: Experience real blockchain mining with configurable difficulty +**🔒 Security**: Industry-standard rate limiting and input validation +**📦 API Versioning**: Future-proof API design with v1 namespace +**✅ Quality**: 90%+ test coverage with automated CI/CD +**📚 Documentation**: Comprehensive guides for users and contributors + +**Upgrade Impact**: This is a breaking release. API endpoints have moved to `/api/v1` and block creation now requires mining. See Migration Guide above. + +### v1.0.0 - Initial Release +First public release of ChainForge. Provides core blockchain functionality with REST API and MongoDB persistence. Educational implementation demonstrating blockchain fundamentals. + +## Links + +- [Repository](https://github.com/Perafan18/chain_forge) +- [Issues](https://github.com/Perafan18/chain_forge/issues) +- [Pull Requests](https://github.com/Perafan18/chain_forge/pulls) + +## Versioning + +We use [Semantic Versioning](https://semver.org/): +- **MAJOR**: Breaking changes (API changes, behavior changes) +- **MINOR**: New features (backward compatible) +- **PATCH**: Bug fixes (backward compatible) diff --git a/CLAUDE.md b/CLAUDE.md index 49d1407..89d7aed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -7,21 +7,37 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co **This is an educational side project** - ChainForge is a learning-focused blockchain implementation NOT intended for production use. The goal is to understand blockchain fundamentals through hands-on implementation. ### Project Goals -- Demonstrate core blockchain concepts (hashing, chain validation, immutability) +- Demonstrate core blockchain concepts (hashing, chain validation, immutability, Proof of Work) - Provide a clean, well-tested Ruby codebase for learning -- Gradually add professional features (PoW, security, testing) as learning exercises -- Maintain simplicity while improving code quality +- Implement professional features (PoW, API security, testing, CI/CD) as learning exercises +- Maintain simplicity and educational value while improving code quality +- Follow software engineering best practices (testing, linting, documentation) ## Project Overview -ChainForge is a blockchain implementation built with Ruby, Sinatra, and MongoDB. It provides a RESTful API for creating blockchain instances, adding blocks, and validating block data integrity. +ChainForge is a blockchain implementation built with Ruby, Sinatra, and MongoDB. It provides a versioned RESTful API (`/api/v1`) for creating blockchain instances, mining blocks with Proof of Work, and validating block data integrity. Version 2 adds professional features like rate limiting, input validation, CI/CD, and comprehensive testing infrastructure. ## Development Environment -- Ruby version: 3.2.2 (managed via rbenv) -- Database: MongoDB (via Mongoid ODM) -- Web framework: Sinatra 4.0 -- Testing: RSpec 3.10 +### Core Dependencies +- **Ruby version**: 3.2.2 (managed via rbenv) +- **Database**: MongoDB (via Mongoid ODM 7.0.5) +- **Web framework**: Sinatra 4.0 with sinatra-contrib (namespace support) +- **Testing**: RSpec 3.10 with SimpleCov coverage reporting +- **Code Quality**: RuboCop 1.57 with rubocop-rspec +- **Security**: Rack::Attack 6.7 for rate limiting +- **Validation**: dry-validation 1.10 for input validation +- **Environment**: dotenv 2.7 for configuration management +- **CI/CD**: GitHub Actions + +### Version 2 Features +- ✅ **Proof of Work (PoW)**: Mining algorithm with configurable difficulty (1-10) +- ✅ **API Versioning**: All endpoints under `/api/v1` namespace +- ✅ **Rate Limiting**: Rack::Attack protection (60 req/min, configurable per endpoint) +- ✅ **Input Validation**: dry-validation with detailed error messages +- ✅ **Environment Configuration**: DEFAULT_DIFFICULTY and other env vars +- ✅ **CI/CD Pipeline**: GitHub Actions with RuboCop + RSpec +- ✅ **Code Quality Tools**: RuboCop linting, SimpleCov coverage (>90%) ## Essential Commands @@ -33,15 +49,22 @@ rbenv local 3.2.2 # Install dependencies bundle install + +# Configure environment +cp .env.example .env +# Edit .env and set DEFAULT_DIFFICULTY, MongoDB config, etc. ``` ### Running the Application ```bash -# Local development +# Local development (requires MongoDB running) ruby main.rb -p 1910 -# Docker (includes MongoDB) +# Docker (includes MongoDB with proper networking) docker-compose up + +# Docker (detached mode) +docker-compose up -d ``` ### Testing @@ -49,14 +72,36 @@ docker-compose up # Run all tests bundle exec rspec +# Run with coverage report +COVERAGE=true bundle exec rspec + +# View coverage report +open coverage/index.html + # Run specific test file bundle exec rspec spec/blockchain_spec.rb bundle exec rspec spec/block_spec.rb +bundle exec rspec spec/api_spec.rb # Run specific test by line number bundle exec rspec spec/blockchain_spec.rb:10 ``` +### Code Quality +```bash +# Run RuboCop linter +bundle exec rubocop + +# Auto-fix RuboCop violations +bundle exec rubocop -a + +# Check specific files +bundle exec rubocop main.rb src/ + +# Full CI pipeline (locally) +bundle exec rubocop && COVERAGE=true bundle exec rspec +``` + ## Architecture ### Core Data Models @@ -64,49 +109,378 @@ bundle exec rspec spec/blockchain_spec.rb:10 The application uses Mongoid ODM with a parent-child relationship between Blockchain and Block: **Blockchain** (`src/blockchain.rb`) -- Contains a collection of blocks (has_many :blocks) -- Automatically creates a genesis block on initialization (after_create hook) -- Validates chain integrity by checking hash consistency between consecutive blocks +- Contains a collection of blocks (`has_many :blocks`) +- Automatically creates a genesis block on initialization (`after_create` hook) +- Genesis block is NOT mined (to speed up blockchain creation) +- Validates chain integrity by checking: + 1. Hash links between consecutive blocks (previous_hash matches) + 2. Each block's calculated hash matches its stored hash + 3. Each block's hash meets its difficulty requirement (`valid_hash?`) - Prevents adding blocks if chain integrity is compromised +- `add_block` method mines blocks using Proof of Work before saving **Block** (`src/block.rb`) -- Belongs to a blockchain (belongs_to :blockchain) -- Contains: index, data, previous_hash, and calculated _hash -- Hash is calculated before validation using SHA256 of: index + timestamp + data + previous_hash -- Provides data validation by recalculating hash and comparing with stored _hash +- Belongs to a blockchain (`belongs_to :blockchain`) +- **Fields**: index, data, previous_hash, _hash, nonce, difficulty, timestamps +- **Hash Calculation**: SHA256 of `index + timestamp + data + previous_hash + nonce` +- **Mining** (`mine_block`): Increments nonce until hash starts with N zeros (N = difficulty) +- **Validation** (`valid_hash?`): Verifies hash meets difficulty requirement +- **Data Validation** (`valid_data?`): Recalculates hash and compares with stored _hash +- Hash is calculated before validation using `before_validation` callback +- Default difficulty read from `ENV['DEFAULT_DIFFICULTY']` (defaults to 2) +- Immutable once created (hash + PoW verification prevents tampering) ### API Endpoints -The Sinatra application (`main.rb`) exposes three endpoints: - -1. `POST /chain` - Creates a new blockchain with genesis block -2. `POST /chain/:id/block` - Adds a block with provided data to specified chain -3. `POST /chain/:id/block/:block_id/valid` - Validates if provided data matches the block's stored hash +The Sinatra application (`main.rb`) exposes versioned endpoints under `/api/v1` namespace: + +**All endpoints are protected by:** +- Rate limiting (Rack::Attack) - Returns 429 when exceeded +- Input validation (dry-validation) - Returns 400 with detailed errors on failure +- Content type enforcement (JSON) + +**Endpoints:** + +1. **POST /api/v1/chain** - Creates a new blockchain with genesis block + - Rate limit: 10 requests/minute per IP + - Returns: `{"id": "blockchain_id"}` + +2. **POST /api/v1/chain/:id/block** - Mines and adds a block to the chain + - Rate limit: 30 requests/minute per IP + - Request body: `{"data": "string", "difficulty": integer (optional, 1-10)}` + - Validates input via `BlockDataContract` + - Uses `DEFAULT_DIFFICULTY` env var if difficulty not provided + - Mines block (PoW) before saving + - Returns: `{"chain_id", "block_id", "block_hash", "nonce", "difficulty"}` + +3. **GET /api/v1/chain/:id/block/:block_id** - Retrieves block details + - No rate limit beyond global 60 req/min + - Returns: Complete block info including mining data (nonce, difficulty, valid_hash) + +4. **POST /api/v1/chain/:id/block/:block_id/valid** - Validates block data + - Request body: `{"data": "string"}` + - Returns: `{"chain_id", "block_id", "valid": boolean}` + +**Root endpoint:** +- `GET /` - Returns "Hello to ChainForge!" (HTML, not JSON) + +### Security & Validation + +**Rate Limiting** (`config/rack_attack.rb`) +- Implemented via Rack::Attack middleware +- Disabled in test environment (`ENV['ENVIRONMENT'] == 'test'`) +- Three throttles: + 1. Global: 60 requests/minute per IP (all endpoints) + 2. Chain creation: 10 requests/minute per IP (POST /api/v1/chain) + 3. Block creation: 30 requests/minute per IP (POST /api/v1/chain/:id/block) +- Returns 429 status with JSON error on limit exceeded +- Memory-based (resets on restart) - not suitable for distributed systems + +**Input Validation** (`src/validators.rb`) +- Uses dry-validation for schema validation +- `BlockDataContract`: + - `data`: required, must be filled string + - `difficulty`: optional, must be integer between 1 and 10 +- Returns 400 status with structured errors: `{"errors": {"field": ["message"]}}` +- Validation happens before mining (saves CPU if invalid) ### Database Configuration MongoDB connection is configured via `config/mongoid.yml` and uses environment variables: -- `MONGO_DB_NAME` - Database name -- `MONGO_DB_HOST` - MongoDB host -- `MONGO_DB_PORT` - MongoDB port -- `ENVIRONMENT` - Rails environment (development/test) +- `MONGO_DB_NAME` - Database name (chain_forge / chain_forge_test) +- `MONGO_DB_HOST` - MongoDB host (localhost / mongodb service in Docker) +- `MONGO_DB_PORT` - MongoDB port (27017) +- `ENVIRONMENT` - Runtime environment (development / test / production) +- `DEFAULT_DIFFICULTY` - Default mining difficulty 1-10 (defaults to 2) -Environment variables should be defined in `.env` for development and `.env.test` for testing. +Environment variables: +- Development: `.env` file (NOT tracked in git, use `.env.example` as template) +- Test: `.env.test` file (tracked in git) +- Production: Set environment variables directly (Docker, Heroku, etc.) ### Key Implementation Details -- Blocks automatically calculate their hash on validation (before_validation callback) -- The genesis block always has index 0, data "Genesis Block", and previous_hash "0" -- Chain integrity validation checks that each block's previous_hash matches the prior block's hash AND that the current block's stored hash matches its calculated hash -- The Block model uses `field :_hash, type: String, as: :hash` to avoid conflicts with Ruby's hash method -- Adding a block fails if the blockchain's integrity is invalid +**Proof of Work:** +- Blocks are mined by incrementing nonce until hash meets difficulty target +- Target: Hash must start with N leading zeros (N = difficulty) +- Mining is computationally expensive (difficulty 5+ can take minutes) +- Genesis blocks are NOT mined (difficulty ignored for index 0) +- Difficulty can be: + 1. Specified per-block via API (validated 1-10) + 2. Uses DEFAULT_DIFFICULTY env var if not specified + 3. Defaults to 2 if env var not set + +**Chain Integrity:** +- Validation now includes three checks: + 1. `previous_hash` matches prior block's `_hash` + 2. Current block's `_hash` matches its calculated hash + 3. Current block's `_hash` meets difficulty requirement (`valid_hash?`) +- Adding a block fails if any integrity check fails + +**Block Model:** +- Uses `field :_hash, type: String, as: :hash` to avoid conflicts with Ruby's hash method +- Accesses hash via `block._hash` in code, `block.hash` in MongoDB +- Uses `field :difficulty, default: -> { ENV.fetch('DEFAULT_DIFFICULTY', '2').to_i }` +- Lambda ensures environment is read at runtime, not parse time + +**API Response Formats:** +- Success (200): JSON with requested data +- Validation Error (400): `{"errors": {"field": ["message", ...]}}` +- Not Found (404): Default Sinatra error handling +- Unprocessable (422): Used for difficulty validation (deprecated in v2, now uses 400) +- Rate Limit (429): `{"error": "Rate limit exceeded. Please try again later."}` +- Server Error (500): Default Sinatra error handling + +**Helpers:** +- `parse_json_body`: Parses request body as JSON +- `find_block_chain`: Finds blockchain by ID, raises if not found ## Development Guidelines When contributing to this project: -1. **Maintain Educational Value**: Keep code readable and well-commented for learning purposes -2. **Test Coverage**: All new features must include RSpec tests -3. **Simplicity First**: Prefer clear, simple implementations over complex optimizations -4. **Documentation**: Update README.md and CLAUDE.md when adding features -5. **No Production Shortcuts**: Even though this is educational, implement features correctly (no mocking security, etc.) +1. **Maintain Educational Value**: + - Keep code readable and well-commented for learning purposes + - Explain "why" in comments, not just "what" + - Demonstrate concepts clearly + - Prioritize clarity over performance optimizations + +2. **Test Coverage**: + - All new features MUST include RSpec tests + - Maintain >90% test coverage (tracked by SimpleCov) + - Test happy paths AND error cases + - Run `COVERAGE=true bundle exec rspec` before committing + - Current: 17 examples, 0 failures + +3. **Code Quality**: + - Follow RuboCop style guidelines (`.rubocop.yml`) + - Run `bundle exec rubocop` before committing + - Auto-fix when possible: `bundle exec rubocop -a` + - All PRs must pass RuboCop checks (enforced by CI) + +4. **Simplicity First**: + - Prefer clear, simple implementations over complex optimizations + - This is a learning project, not a performance benchmark + - Document any complex algorithms (e.g., Proof of Work) + +5. **Documentation**: + - Update README.md when adding user-facing features + - Update CLAUDE.md when changing architecture/development workflow + - Update CHANGELOG.md for all changes + - Add inline code comments for complex logic + +6. **No Production Shortcuts**: + - Even though this is educational, implement features correctly + - No mocking security features (rate limiting, validation) + - Use real MongoDB (not in-memory) + - Proper error handling + +7. **API Versioning**: + - ALL new endpoints must be under `/api/v1` namespace + - Use Sinatra `namespace '/api/v1'` blocks + - Never add endpoints to root path (except GET /) + +8. **Environment Configuration**: + - Use environment variables for ALL configuration + - Never hardcode values (ports, database names, difficulty, etc.) + - Provide sensible defaults with `ENV.fetch('VAR', 'default')` + - Document new env vars in README.md and .env.example + +9. **Security & Validation**: + - All public endpoints must have rate limiting + - All user inputs must be validated (dry-validation contracts) + - Return proper HTTP status codes (400, 422, 429, etc.) + - Include detailed error messages for debugging + +10. **CI/CD**: + - All PRs must pass GitHub Actions checks + - Pipeline runs: RuboCop + RSpec with MongoDB service + - No merging without green CI + - Fix linting issues, don't disable cops (unless justified) + +## Testing Strategy + +### Test Organization +- `spec/block_spec.rb` - Block model unit tests (hashing, mining, validation) +- `spec/blockchain_spec.rb` - Blockchain model tests (integrity, add_block, genesis) +- `spec/api_spec.rb` - API integration tests (all endpoints, error cases) + +### Test Environment +- Uses `.env.test` configuration +- Separate test database: `chain_forge_test` +- Rate limiting DISABLED in tests (for speed and reliability) +- SimpleCov tracks coverage (aim for >90%) + +### Testing Best Practices +- Test behavior, not implementation +- Use descriptive test names +- Test edge cases (empty data, invalid difficulty, etc.) +- Test error handling (404, 400, 429) +- Mock/stub external dependencies only when necessary +- Keep tests fast (use difficulty 1-2 for mining tests) + +## CI/CD Pipeline + +### GitHub Actions Workflow +Location: `.github/workflows/ci.yml` + +**Triggers:** +- Every push to any branch +- Every pull request + +**Jobs:** +1. **Lint**: Runs RuboCop style checks +2. **Test**: Runs RSpec test suite with MongoDB service + +**MongoDB Service:** +- Runs in Docker container +- Configured for test environment +- Matches `.env.test` configuration + +**Failure Handling:** +- PR cannot be merged if CI fails +- Fix linting issues or tests before merge +- Check GitHub Actions logs for details + +## Common Development Tasks + +### Adding a New Endpoint +1. Add route in `namespace '/api/v1'` block in `main.rb` +2. Add rate limiting rule in `config/rack_attack.rb` +3. Create validation contract in `src/validators.rb` (if needed) +4. Add tests in `spec/api_spec.rb` +5. Update README.md API Reference +6. Update API_DOCUMENTATION.md +7. Run tests and RuboCop + +### Modifying Block/Blockchain Models +1. Update model in `src/block.rb` or `src/blockchain.rb` +2. Update tests in `spec/block_spec.rb` or `spec/blockchain_spec.rb` +3. Consider migration impact (MongoDB schema changes) +4. Update documentation (README.md Architecture section) +5. Run tests to ensure backward compatibility + +### Changing Environment Variables +1. Update `.env.example` with new var and comment +2. Update `.env.test` if test-specific +3. Update `README.md` Configuration section +4. Update `CLAUDE.md` (this file) +5. Update code to use `ENV.fetch('VAR', 'default')` + +### Adjusting Rate Limits +1. Edit `config/rack_attack.rb` +2. Update README.md Rate Limiting table +3. Update API_DOCUMENTATION.md +4. Consider impact on user experience +5. Test with actual API calls + +## Troubleshooting + +### Common Issues + +**MongoDB Connection Errors** +- Ensure MongoDB is running: `docker-compose up -d mongodb` +- Check `.env` has correct MONGO_DB_HOST, PORT, NAME +- For Docker: use `host: mongodb` not `localhost` + +**Rate Limiting in Tests** +- Ensure `.env.test` has `ENVIRONMENT=test` +- Check `main.rb` has: `use Rack::Attack unless ENV['ENVIRONMENT'] == 'test'` +- Rate limiting should be disabled in test environment + +**RuboCop Failures** +- Run `bundle exec rubocop -a` to auto-fix +- Check `.rubocop.yml` for project-specific rules +- Don't disable cops without good reason +- Add `# rubocop:disable CopName` comment only when necessary + +**Mining Takes Too Long** +- Use lower difficulty in development (1-3) +- Set `DEFAULT_DIFFICULTY=2` in `.env` +- Avoid difficulty >5 in tests +- Consider mocking `mine_block` in tests (with caution) + +**SimpleCov Not Generating Report** +- Run with: `COVERAGE=true bundle exec rspec` +- Check `coverage/` directory is created +- Check `.gitignore` includes `/coverage` +- Coverage only generated when explicitly enabled + +## Project Structure + +``` +chain_forge/ +├── .env.example # Environment variable template +├── .env.test # Test environment configuration +├── .rubocop.yml # RuboCop linting rules +├── Gemfile # Ruby dependencies +├── docker-compose.yml # Docker configuration +├── main.rb # Sinatra application (API endpoints) +├── config/ +│ ├── mongoid.yml # MongoDB configuration +│ └── rack_attack.rb # Rate limiting rules +├── src/ +│ ├── blockchain.rb # Blockchain model +│ ├── block.rb # Block model with PoW +│ └── validators.rb # dry-validation contracts +├── spec/ +│ ├── api_spec.rb # API integration tests +│ ├── blockchain_spec.rb # Blockchain model tests +│ ├── block_spec.rb # Block model tests +│ └── spec_helper.rb # RSpec configuration +├── .github/ +│ └── workflows/ +│ └── ci.yml # GitHub Actions CI pipeline +└── docs/ + ├── README.md # Main user documentation + ├── CLAUDE.md # This file (Claude Code guidance) + ├── CHANGELOG.md # Version history + ├── CONTRIBUTING.md # Contribution guidelines + ├── SECURITY.md # Security policies + ├── API_DOCUMENTATION.md # Complete API reference + └── DEPLOYMENT.md # Production deployment guide +``` + +## Educational Objectives + +This project demonstrates: +1. **Blockchain Fundamentals**: Hash linking, chain validation, immutability +2. **Proof of Work**: Mining algorithm, difficulty adjustment, computational security +3. **Cryptographic Hashing**: SHA256, hash collisions (practical impossibility) +4. **API Design**: RESTful principles, versioning, error handling +5. **Security**: Rate limiting, input validation, attack prevention +6. **Testing**: Unit tests, integration tests, coverage reporting +7. **Code Quality**: Linting, style enforcement, maintainability +8. **CI/CD**: Automated testing, continuous integration +9. **Ruby/Sinatra**: Web framework, routing, middleware +10. **MongoDB/Mongoid**: NoSQL databases, ODM patterns, document modeling + +## Differences from Production Blockchains + +ChainForge is educational and differs from production blockchains in: + +**Simplified:** +- No peer-to-peer networking (single server) +- No distributed consensus (no other nodes) +- Fixed difficulty (no dynamic adjustment) +- Single SHA256 (Bitcoin uses double SHA256) +- No merkle trees (transactions not grouped) +- No block rewards or mining incentives +- No transaction signing or public/private keys +- No mempool or transaction queuing + +**Educational Focus:** +- Demonstrates core concepts clearly +- Keeps code readable and understandable +- Prioritizes learning over performance +- Well-documented and tested +- Suitable for studying blockchain fundamentals + +**Not Suitable For:** +- Production use +- Cryptocurrency implementation +- High-value data storage +- Distributed systems +- Public blockchain networks + +Use this project to learn blockchain concepts, then study real implementations (Bitcoin, Ethereum) to understand production complexity. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..425169d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,290 @@ +# Contributing to ChainForge + +Thank you for your interest in contributing! ChainForge is an educational project focused on blockchain fundamentals. + +## Code of Conduct + +Be respectful, constructive, and helpful. This is a learning environment. + +## Development Setup + +### Prerequisites +- Ruby 3.2.2 (via rbenv) +- MongoDB +- Git + +### Setup Steps + +```bash +# Clone repository +git clone https://github.com/Perafan18/chain_forge.git +cd chain_forge + +# Install Ruby version +rbenv install 3.2.2 +rbenv local 3.2.2 + +# Install dependencies +bundle install + +# Configure environment +cp .env.example .env +# Edit .env: set DEFAULT_DIFFICULTY, MongoDB config + +# Start MongoDB +docker-compose up -d mongodb + +# Run tests +bundle exec rspec +``` + +## Development Workflow + +### 1. Create a Branch + +```bash +git checkout -b feature/your-feature-name +``` + +Branch naming conventions: +- `feature/` - New features +- `fix/` - Bug fixes +- `docs/` - Documentation only +- `refactor/` - Code refactoring +- `test/` - Test improvements + +### 2. Make Changes + +- Write clear, readable code (educational value is key) +- Add/update tests for new features +- Follow RuboCop style guidelines +- Update documentation + +### 3. Test Your Changes + +```bash +# Run RuboCop +bundle exec rubocop + +# Auto-fix style issues +bundle exec rubocop -a + +# Run tests with coverage +COVERAGE=true bundle exec rspec + +# Aim for >90% coverage +open coverage/index.html +``` + +### 4. Commit + +```bash +git add . +git commit -m "feat: Clear description of changes" +``` + +Commit message format: +- `feat:` - New feature +- `fix:` - Bug fix +- `docs:` - Documentation +- `refactor:` - Code refactoring +- `test:` - Test changes +- `chore:` - Maintenance + +### 5. Push and Create PR + +```bash +git push origin feature/your-feature-name +``` + +Then open a Pull Request on GitHub with: +- Clear description of changes +- Why the change is needed +- How to test it +- Any breaking changes + +## Code Style + +### Ruby Style + +Follow RuboCop guidelines (`.rubocop.yml`): +- Use single quotes for strings +- 2-space indentation +- Max line length: 120 characters +- Frozen string literal comments + +### Code Quality + +- Keep methods short and focused +- Use meaningful variable names +- Comment complex logic (explain "why", not "what") +- Avoid premature optimization +- Maintain educational clarity + +## Testing Guidelines + +### Test Structure + +```ruby +RSpec.describe Feature do + describe '#method' do + context 'when condition' do + it 'does something specific' do + # Arrange + object = create_object + + # Act + result = object.method + + # Assert + expect(result).to eq(expected) + end + end + end +end +``` + +### Testing Best Practices + +- **Test behavior, not implementation** +- **Use descriptive test names**: "returns error when data is empty" +- **Test edge cases**: empty strings, nil values, boundary conditions +- **Test error handling**: 404, 400, 429 status codes +- **Mock external dependencies**: but use real MongoDB in tests +- **Keep tests fast**: Use difficulty 1-2 for mining tests + +### Coverage Requirements + +- Aim for >90% test coverage +- All new features must include tests +- Test both happy paths and error cases +- Run `COVERAGE=true bundle exec rspec` before submitting + +## Documentation + +### When to Update Docs + +Update documentation when: +- Adding new features +- Changing API endpoints +- Modifying environment variables +- Changing architecture +- Adding dependencies + +### Files to Update + +- **README.md**: User-facing features and API +- **CLAUDE.md**: Developer architecture and workflow +- **CHANGELOG.md**: All changes (following Keep a Changelog format) +- **API_DOCUMENTATION.md**: Complete endpoint changes +- **Inline comments**: Complex logic + +## Educational Focus + +Remember, this is a learning project: + +### Prioritize +- ✅ **Clarity**: Clear, understandable code +- ✅ **Comments**: Explain complex concepts +- ✅ **Simplicity**: Simple implementations +- ✅ **Documentation**: Well-documented features + +### Avoid +- ❌ **Premature optimization**: Don't sacrifice clarity for speed +- ❌ **Complex abstractions**: Keep it simple +- ❌ **Production shortcuts**: Implement correctly, even if educational + +## Pull Request Process + +### Before Submitting + +- [ ] All tests pass (`bundle exec rspec`) +- [ ] RuboCop passes (`bundle exec rubocop`) +- [ ] Coverage >90% (`COVERAGE=true bundle exec rspec`) +- [ ] Documentation updated +- [ ] CHANGELOG.md updated +- [ ] Commit messages are clear +- [ ] No `.env` or sensitive data committed + +### PR Review Process + +1. **Automated Checks**: GitHub Actions runs RuboCop + RSpec +2. **Code Review**: Maintainer reviews code quality and tests +3. **Feedback**: Address any requested changes +4. **Approval**: Once approved, PR will be merged +5. **Merge**: Squash and merge to main branch + +### Getting Feedback + +- Be patient, reviews may take a few days +- Respond to feedback constructively +- Ask questions if feedback is unclear +- Make requested changes promptly + +## Common Contribution Areas + +### Good First Issues + +- Documentation improvements +- Test coverage improvements +- Bug fixes +- Code comments +- Example scripts + +### Advanced Contributions + +- New API endpoints +- Performance optimizations +- Security enhancements +- Monitoring features +- Advanced PoW features + +## API Changes + +### Adding New Endpoints + +When adding API endpoints: + +1. Use `/api/v1` namespace +2. Add rate limiting in `config/rack_attack.rb` +3. Create validation contract in `src/validators.rb` +4. Add tests in `spec/api_spec.rb` +5. Update README.md and API_DOCUMENTATION.md +6. Consider backward compatibility + +### Breaking Changes + +Avoid breaking changes when possible. If necessary: + +1. Discuss in issue first +2. Document in CHANGELOG.md (Breaking Changes section) +3. Update README.md with migration guide +4. Increment major version (2.x.x → 3.0.0) + +## Environment Variables + +### Adding New Env Vars + +When adding environment variables: + +1. Add to `.env.example` with comment +2. Add to `.env.test` if needed for tests +3. Document in README.md Configuration section +4. Document in CLAUDE.md +5. Use `ENV.fetch('VAR', 'default')` in code + +## Questions? + +- Open an issue for discussion +- Ask in pull request comments +- Check existing documentation +- Review similar contributions + +## Recognition + +Contributors will be: +- Listed in git commit history +- Mentioned in release notes +- Appreciated for making blockchain education better! + +Thank you for contributing to ChainForge! 🎉 diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..0fe8c96 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,559 @@ +# Deployment Guide + +Production deployment guide for ChainForge. + +**⚠️ Warning:** ChainForge is an educational project. Use caution when deploying to production. + +## Prerequisites + +- Linux server (Ubuntu 20.04+ recommended) +- Ruby 3.2.2 +- MongoDB 4.4+ +- Nginx or Apache +- SSL certificate +- Domain name + +## Environment Setup + +### 1. Server Preparation + +```bash +# Update system +sudo apt update && sudo apt upgrade -y + +# Install dependencies +sudo apt install -y build-essential git curl libssl-dev libreadline-dev zlib1g-dev + +# Install rbenv +curl -fsSL https://github.com/rbenv/rbenv-installer/raw/main/bin/rbenv-installer | bash + +# Add to ~/.bashrc +echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc +echo 'eval "$(rbenv init -)"' >> ~/.bashrc +source ~/.bashrc + +# Install Ruby 3.2.2 +rbenv install 3.2.2 +rbenv global 3.2.2 +``` + +### 2. MongoDB Installation + +```bash +# Import MongoDB GPG key +wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add - + +# Add MongoDB repository +echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list + +# Install MongoDB +sudo apt update +sudo apt install -y mongodb-org + +# Start MongoDB +sudo systemctl start mongod +sudo systemctl enable mongod +``` + +### 3. MongoDB Security + +```bash +# Connect to MongoDB +mongo + +# Create admin user +use admin +db.createUser({ + user: "admin", + pwd: "STRONG_PASSWORD_HERE", + roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] +}) + +# Create app user +use chain_forge +db.createUser({ + user: "chainforge_user", + pwd: "STRONG_PASSWORD_HERE", + roles: [ { role: "readWrite", db: "chain_forge" } ] +}) + +exit +``` + +Enable authentication in `/etc/mongod.conf`: +```yaml +security: + authorization: enabled +``` + +Restart MongoDB: +```bash +sudo systemctl restart mongod +``` + +## Application Deployment + +### 1. Clone Repository + +```bash +cd /var/www +sudo git clone https://github.com/Perafan18/chain_forge.git +cd chain_forge +sudo chown -R $USER:$USER . +``` + +### 2. Install Dependencies + +```bash +bundle install --deployment --without development test +``` + +### 3. Environment Configuration + +Create `.env` file: +```bash +cat > .env << EOF +MONGO_DB_NAME=chain_forge +MONGO_DB_HOST=localhost +MONGO_DB_PORT=27017 +MONGO_DB_USER=chainforge_user +MONGO_DB_PASSWORD=STRONG_PASSWORD_HERE +ENVIRONMENT=production +DEFAULT_DIFFICULTY=4 +RACK_ENV=production +EOF + +chmod 600 .env +``` + +### 4. MongoDB Configuration + +Update `config/mongoid.yml` for production: +```yaml +production: + clients: + default: + database: <%= ENV['MONGO_DB_NAME'] %> + hosts: + - <%= "#{ENV['MONGO_DB_HOST']}:#{ENV['MONGO_DB_PORT']}" %> + options: + user: <%= ENV['MONGO_DB_USER'] %> + password: <%= ENV['MONGO_DB_PASSWORD'] %> + auth_source: admin +``` + +## Process Management + +### Using Systemd + +Create `/etc/systemd/system/chainforge.service`: +```ini +[Unit] +Description=ChainForge Blockchain API +After=network.target mongod.service + +[Service] +Type=simple +User=www-data +WorkingDirectory=/var/www/chain_forge +Environment=RACK_ENV=production +ExecStart=/home/www-data/.rbenv/shims/bundle exec rackup -p 1910 -o 127.0.0.1 +Restart=on-failure +RestartSec=10 + +[Install] +WantedBy=multi-user.target +``` + +Enable and start service: +```bash +sudo systemctl daemon-reload +sudo systemctl enable chainforge +sudo systemctl start chainforge +sudo systemctl status chainforge +``` + +## Reverse Proxy + +### Nginx Configuration + +Create `/etc/nginx/sites-available/chainforge`: +```nginx +# Rate limiting +limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m; +limit_req_zone $binary_remote_addr zone=chain:10m rate=10r/m; +limit_req_zone $binary_remote_addr zone=block:10m rate=30r/m; + +upstream chainforge { + server 127.0.0.1:1910 fail_timeout=0; +} + +server { + listen 80; + server_name api.yourdomain.com; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name api.yourdomain.com; + + # SSL Configuration + ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # Security Headers + add_header Strict-Transport-Security "max-age=31536000" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + + # Logging + access_log /var/log/nginx/chainforge_access.log; + error_log /var/log/nginx/chainforge_error.log; + + # Proxy to application + location /api/v1/ { + limit_req zone=api burst=10 nodelay; + + proxy_pass http://chainforge; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Timeouts (mining can take time) + proxy_connect_timeout 60s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # Rate limiting for specific endpoints + location /api/v1/chain { + limit_req zone=chain burst=5 nodelay; + proxy_pass http://chainforge; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location ~ /api/v1/chain/.*/block$ { + limit_req zone=block burst=10 nodelay; + proxy_pass http://chainforge; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # Longer timeout for mining + proxy_read_timeout 600s; + } +} +``` + +Enable site: +```bash +sudo ln -s /etc/nginx/sites-available/chainforge /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl reload nginx +``` + +## SSL Certificate + +### Using Let's Encrypt + +```bash +# Install certbot +sudo apt install -y certbot python3-certbot-nginx + +# Obtain certificate +sudo certbot --nginx -d api.yourdomain.com + +# Auto-renewal (already configured by certbot) +sudo certbot renew --dry-run +``` + +## Firewall + +```bash +# Allow SSH, HTTP, HTTPS +sudo ufw allow 22/tcp +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp + +# Block direct access to app port +sudo ufw deny 1910/tcp + +# Enable firewall +sudo ufw enable +``` + +## Monitoring + +### Application Logs + +```bash +# View application logs +sudo journalctl -u chainforge -f + +# View nginx logs +sudo tail -f /var/log/nginx/chainforge_access.log +sudo tail -f /var/log/nginx/chainforge_error.log +``` + +### MongoDB Monitoring + +```bash +# MongoDB logs +sudo tail -f /var/log/mongodb/mongod.log + +# Connection check +mongo --host localhost --port 27017 -u admin -p --authenticationDatabase admin +``` + +### System Resources + +```bash +# CPU and memory +htop + +# Disk space +df -h + +# MongoDB disk usage +du -sh /var/lib/mongodb +``` + +## Backup + +### MongoDB Backup + +```bash +# Create backup script +cat > /usr/local/bin/backup-chainforge.sh << 'EOF' +#!/bin/bash +DATE=$(date +%Y%m%d_%H%M%S) +BACKUP_DIR=/var/backups/chainforge +mkdir -p $BACKUP_DIR + +mongodump \ + --host localhost \ + --port 27017 \ + --db chain_forge \ + --username chainforge_user \ + --password STRONG_PASSWORD_HERE \ + --authenticationDatabase admin \ + --out $BACKUP_DIR/backup_$DATE + +# Keep only last 7 days +find $BACKUP_DIR -type d -mtime +7 -exec rm -rf {} + +EOF + +chmod +x /usr/local/bin/backup-chainforge.sh +``` + +Add to crontab: +```bash +# Daily backup at 2 AM +0 2 * * * /usr/local/bin/backup-chainforge.sh +``` + +## Performance Tuning + +### MongoDB Indexes + +```javascript +// Connect to MongoDB +mongo -u chainforge_user -p --authenticationDatabase admin + +use chain_forge + +// Create indexes +db.blocks.createIndex({ "blockchain_id": 1 }) +db.blocks.createIndex({ "index": 1 }) +db.blocks.createIndex({ "_hash": 1 }) +db.blockchains.createIndex({ "created_at": -1 }) +``` + +### Application Tuning + +Update `.env`: +```bash +# Increase default difficulty for production +DEFAULT_DIFFICULTY=4 + +# Production environment +RACK_ENV=production +``` + +### System Tuning + +```bash +# Increase file descriptors +echo "* soft nofile 65536" | sudo tee -a /etc/security/limits.conf +echo "* hard nofile 65536" | sudo tee -a /etc/security/limits.conf + +# MongoDB tuning +echo "never" | sudo tee /sys/kernel/mm/transparent_hugepage/enabled +echo "never" | sudo tee /sys/kernel/mm/transparent_hugepage/defrag +``` + +## Security Checklist + +- [ ] MongoDB authentication enabled +- [ ] Strong passwords configured +- [ ] SSL/TLS certificates installed +- [ ] Firewall configured +- [ ] Application running as non-root user +- [ ] `.env` file permissions set to 600 +- [ ] Nginx security headers configured +- [ ] Rate limiting enabled +- [ ] Regular backups scheduled +- [ ] Monitoring configured +- [ ] Log rotation enabled +- [ ] System updates automated + +## Troubleshooting + +### Application Won't Start + +```bash +# Check logs +sudo journalctl -u chainforge -n 50 + +# Check if port is in use +sudo lsof -i :1910 + +# Check MongoDB connection +mongo -u chainforge_user -p --authenticationDatabase admin + +# Check environment variables +sudo systemctl cat chainforge +``` + +### High CPU Usage + +```bash +# Check mining difficulty +grep DEFAULT_DIFFICULTY /var/www/chain_forge/.env + +# Monitor active processes +top -u www-data + +# Check for stuck mining operations +sudo journalctl -u chainforge | grep "mine_block" +``` + +### Database Issues + +```bash +# Check MongoDB status +sudo systemctl status mongod + +# Check disk space +df -h /var/lib/mongodb + +# Repair database (if needed) +sudo systemctl stop mongod +mongod --repair +sudo systemctl start mongod +``` + +## Scaling Considerations + +### Vertical Scaling + +- Increase server resources (CPU, RAM) +- Use SSD for MongoDB data directory +- Optimize MongoDB queries with indexes + +### Horizontal Scaling + +**Not supported** - ChainForge is a single-instance application: +- No distributed consensus +- No peer-to-peer networking +- Rate limiting is memory-based + +For production blockchain, consider: +- Ethereum +- Hyperledger Fabric +- Cosmos SDK + +## Updates + +### Application Updates + +```bash +cd /var/www/chain_forge + +# Backup first +sudo -u www-data mongodump ... + +# Pull latest code +git fetch origin +git checkout v2.0.0 # or specific version + +# Update dependencies +bundle install --deployment + +# Restart application +sudo systemctl restart chainforge +``` + +### Security Updates + +```bash +# System updates +sudo apt update && sudo apt upgrade -y + +# Ruby gems +bundle update --conservative + +# Audit vulnerabilities +gem install bundler-audit +bundle audit check --update +``` + +## Maintenance + +### Log Rotation + +Create `/etc/logrotate.d/chainforge`: +``` +/var/log/nginx/chainforge_*.log { + daily + missingok + rotate 14 + compress + delaycompress + notifempty + create 0640 www-data adm + sharedscripts + postrotate + [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` + endscript +} +``` + +### Health Checks + +```bash +# Check API health +curl https://api.yourdomain.com/ + +# Check MongoDB +mongo -u admin -p --authenticationDatabase admin --eval "db.adminCommand('ping')" + +# Check disk space +df -h + +# Check memory +free -h +``` + +## Support + +For deployment issues: +- GitHub Issues: https://github.com/Perafan18/chain_forge/issues +- Documentation: README.md, SECURITY.md diff --git a/README.md b/README.md index d8c4653..b7b64c6 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,94 @@ # ChainForge -> **Educational Side Project**: ChainForge is a learning-focused blockchain implementation built to understand core blockchain concepts like cryptographic hashing, chain validation, and distributed ledger fundamentals. This is NOT intended for production use. +> **Educational Side Project**: ChainForge is a learning-focused blockchain implementation built to understand core blockchain concepts like cryptographic hashing, Proof of Work mining, chain validation, and distributed ledger fundamentals. This is NOT intended for production use. [![Ruby](https://img.shields.io/badge/Ruby-3.2.2-red.svg)](https://www.ruby-lang.org/) [![MongoDB](https://img.shields.io/badge/MongoDB-Latest-green.svg)](https://www.mongodb.com/) [![Sinatra](https://img.shields.io/badge/Sinatra-4.0-blue.svg)](http://sinatrarb.com/) +[![CI](https://img.shields.io/badge/CI-GitHub%20Actions-brightgreen.svg)](https://github.com/Perafan18/chain_forge/actions) -A simple blockchain implementation with REST API built using Ruby, Sinatra, and MongoDB. Explore how blocks are linked through cryptographic hashes and how chain integrity is maintained. +A blockchain implementation with REST API built using Ruby, Sinatra, and MongoDB. Explore how blocks are linked through cryptographic hashes, how Proof of Work mining secures the chain, and how API security works. ## Features +### Core Blockchain - ✅ Create independent blockchain instances - ✅ Add blocks with custom data - ✅ SHA256 cryptographic hashing - ✅ Chain integrity validation - ✅ Genesis block auto-generation -- ✅ RESTful API -- 🚧 Advanced features (planned for v2) -## Setup +### Version 2 Features +- ✅ **Proof of Work (PoW)** mining algorithm with configurable difficulty +- ✅ **API Versioning** - All endpoints under `/api/v1` +- ✅ **Rate Limiting** - Rack::Attack protection (60 req/min) +- ✅ **Input Validation** - dry-validation with detailed errors +- ✅ **Environment Configuration** - Configurable mining difficulty +- ✅ **CI/CD Pipeline** - GitHub Actions with automated testing +- ✅ **Code Quality** - RuboCop linting and SimpleCov coverage -### Install ruby 3.2.2 +## Quick Start + +### Prerequisites + +- Ruby 3.2.2 +- MongoDB +- Docker (optional) + +### Installation + +1. **Install Ruby 3.2.2** ```bash rbenv install 3.2.2 rbenv local 3.2.2 ``` -### Install dependencies +2. **Install Dependencies** ```bash bundle install ``` +3. **Configure Environment** + +```bash +cp .env.example .env +``` + +Edit `.env` and configure: +- `MONGO_DB_NAME` - Database name (default: chain_forge) +- `MONGO_DB_HOST` - MongoDB host (default: localhost) +- `MONGO_DB_PORT` - MongoDB port (default: 27017) +- `DEFAULT_DIFFICULTY` - Mining difficulty 1-10 (default: 2) +- `ENVIRONMENT` - Runtime environment (development/test/production) + +4. **Start MongoDB** + +```bash +# Using Docker (recommended) +docker-compose up -d mongodb + +# Or install locally +brew install mongodb-community +brew services start mongodb-community +``` + +5. **Run the Application** + +```bash +ruby main.rb -p 1910 +``` + +Visit http://localhost:1910 to verify it's running. + ### Using Docker (Recommended) ```bash docker-compose up ``` -This will start both the application and MongoDB. +This starts both the application and MongoDB with proper networking. ## Development @@ -49,26 +98,57 @@ This will start both the application and MongoDB. # Run all tests bundle exec rspec -# Run specific test file -bundle exec rspec spec/blockchain_spec.rb +# Run with coverage report +COVERAGE=true bundle exec rspec + +# View coverage +open coverage/index.html ``` -### Run Application +### Code Quality ```bash -# Local development (requires MongoDB running) -ruby main.rb -p 1910 +# Run RuboCop linter +bundle exec rubocop -# With Docker -docker-compose up +# Auto-fix RuboCop issues +bundle exec rubocop -a ``` +### Continuous Integration + +This project uses GitHub Actions for automated testing. Each push and PR triggers: +- ✅ RuboCop style checks +- ✅ RSpec test suite (17 examples) +- ✅ SimpleCov coverage reporting +- ✅ MongoDB integration tests + +See `.github/workflows/ci.yml` for pipeline configuration. + ## API Reference +All endpoints are prefixed with `/api/v1` and protected by rate limiting. + +### Rate Limiting + +| Endpoint Pattern | Limit | Window | +|-----------------|-------|--------| +| All endpoints | 60 requests | 1 minute | +| POST /api/v1/chain | 10 requests | 1 minute | +| POST /api/v1/chain/:id/block | 30 requests | 1 minute | + +When rate limit is exceeded: +```json +{ + "error": "Rate limit exceeded. Please try again later." +} +``` +**HTTP Status**: 429 (Too Many Requests) + ### Create a New Blockchain ```bash -curl -X POST http://localhost:1910/chain +curl -X POST http://localhost:1910/api/v1/chain ``` **Response:** @@ -76,29 +156,84 @@ curl -X POST http://localhost:1910/chain {"id": "507f1f77bcf86cd799439011"} ``` -### Add a Block to Chain +**Rate Limit:** 10 requests/minute per IP + +--- + +### Add a Block to Chain (Mine) ```bash -curl -X POST http://localhost:1910/chain/:chain_id/block \ +curl -X POST http://localhost:1910/api/v1/chain/507f1f77bcf86cd799439011/block \ -H 'Content-Type: application/json' \ - -d '{"data": "your_data"}' + -d '{"data": "Transaction data here", "difficulty": 3}' ``` +**Request Parameters:** +- `data` (required, string): The data to store in the block +- `difficulty` (optional, integer 1-10): Mining difficulty (default: uses `DEFAULT_DIFFICULTY` env var) + **Response:** ```json { "chain_id": "507f1f77bcf86cd799439011", "block_id": "507f191e810c19729de860ea", - "block_hash": "a1b2c3d4..." + "block_hash": "000a1b2c3d4e5f...", + "nonce": 1542, + "difficulty": 3 +} +``` + +**Validation Errors (400):** +```json +{ + "errors": { + "data": ["must be filled"], + "difficulty": ["must be between 1 and 10"] + } +} +``` + +**Rate Limit:** 30 requests/minute per IP + +**Note:** Mining can take time depending on difficulty: +- Difficulty 1-2: ~1 second +- Difficulty 3-4: Few seconds +- Difficulty 5+: Minutes or longer + +--- + +### Get Block Details + +```bash +curl http://localhost:1910/api/v1/chain/507f1f77bcf86cd799439011/block/507f191e810c19729de860ea +``` + +**Response:** +```json +{ + "chain_id": "507f1f77bcf86cd799439011", + "block": { + "id": "507f191e810c19729de860ea", + "index": 1, + "data": "Transaction data here", + "hash": "000a1b2c3d4e5f...", + "previous_hash": "00f8a2b1c3d4...", + "nonce": 1542, + "difficulty": 3, + "timestamp": 1699564821, + "valid_hash": true + } } ``` +--- + ### Validate Block Data ```bash -curl -X POST http://localhost:1910/chain/:chain_id/block/:block_id/valid \ +curl -X POST http://localhost:1910/api/v1/chain/507f1f77bcf86cd799439011/block/507f191e810c19729de860ea/valid \ -H 'Content-Type: application/json' \ - -d '{"data": "your_data"}' + -d '{"data": "Transaction data here"}' ``` **Response:** @@ -110,6 +245,88 @@ curl -X POST http://localhost:1910/chain/:chain_id/block/:block_id/valid \ } ``` +--- + +For complete API documentation, see [API_DOCUMENTATION.md](API_DOCUMENTATION.md). + +## Proof of Work (PoW) + +ChainForge implements a simplified Proof of Work consensus mechanism similar to Bitcoin's mining process. + +### How Mining Works + +1. **Target Calculation**: Based on difficulty level (1-10), the system determines how many leading zeros the hash must have: + - Difficulty 1: Hash must start with `0` + - Difficulty 2: Hash must start with `00` + - Difficulty 3: Hash must start with `000` + - And so on... + +2. **Mining Process**: + ``` + Start with nonce = 0 + Loop: + Calculate: hash = SHA256(index + timestamp + data + previous_hash + nonce) + If hash starts with required zeros: + Mining complete! ✓ + Else: + nonce++ + Try again + ``` + +3. **Mining Example**: + ``` + Block: index=1, data="Hello World", difficulty=3 + Target: Hash must start with "000" + + Attempt 1: nonce=0 -> hash=a1b2c3d4... ✗ (invalid) + Attempt 2: nonce=1 -> hash=9f8e7d6c... ✗ (invalid) + Attempt 3: nonce=2 -> hash=3d4c5b6a... ✗ (invalid) + ... + Attempt 1542: nonce=1542 -> hash=000a1b2c... ✓ (valid!) + ``` + +### Performance Impact + +| Difficulty | Average Time | Leading Zeros | +|-----------|-------------|---------------| +| 1-2 | < 1 second | 0 or 00 | +| 3-4 | Few seconds | 000 or 0000 | +| 5-6 | Minutes | 00000 or 000000 | +| 7+ | Hours+ | 0000000+ | + +**Recommendation**: Use difficulty 2-4 for development and testing. + +### Configuring Difficulty + +**Default (via environment):** +```bash +# .env file +DEFAULT_DIFFICULTY=2 +``` + +**Per-block (via API):** +```bash +curl -X POST http://localhost:1910/api/v1/chain/:id/block \ + -H 'Content-Type: application/json' \ + -d '{"data": "your_data", "difficulty": 4}' +``` + +### Comparison with Bitcoin + +ChainForge's PoW demonstrates the core concept but is simplified: + +| Feature | ChainForge | Bitcoin | +|---------|-----------|---------| +| Hash Algorithm | Single SHA256 | Double SHA256 | +| Difficulty Range | 1-10 (fixed) | Dynamic (adjusts every 2016 blocks) | +| Current Difficulty | ~2-3 leading zeros | ~19 leading zeros (as of 2023) | +| Block Time | Variable | ~10 minutes (target) | +| Difficulty Adjustment | Manual/per-block | Automatic every 2 weeks | +| Merkle Trees | No | Yes | +| Block Rewards | No | Yes (currently 6.25 BTC) | + +**Educational Note**: This implementation demonstrates PoW fundamentals. Real blockchains include additional complexity like dynamic difficulty adjustment, merkle trees for transaction verification, and sophisticated networking protocols. + ## Architecture ### Core Models @@ -117,23 +334,153 @@ curl -X POST http://localhost:1910/chain/:chain_id/block/:block_id/valid \ **Blockchain** (`src/blockchain.rb`) - Contains a collection of blocks (MongoDB: `has_many :blocks`) - Automatically creates genesis block on initialization -- Validates chain integrity by checking hash links between consecutive blocks +- Validates chain integrity by checking: + - Hash links between consecutive blocks + - Each block's hash matches its calculated hash + - Each block's hash meets its difficulty requirement (PoW) +- Genesis block is NOT mined (to speed up creation) **Block** (`src/block.rb`) -- Contains: index, data, previous_hash, and calculated SHA256 hash -- Hash is computed from: `index + timestamp + data + previous_hash` -- Immutable once created (hash verification prevents tampering) +- **Fields**: index, data, previous_hash, calculated SHA256 hash, nonce, difficulty, timestamp +- **Hash Calculation**: `SHA256(index + timestamp + data + previous_hash + nonce)` +- **Mining**: `mine_block` method increments nonce until valid hash found +- **Validation**: `valid_hash?` verifies hash meets difficulty requirement +- **Immutability**: Hash and PoW verification prevents tampering ### How It Works -1. **Genesis Block**: Each blockchain starts with block index 0 -2. **Adding Blocks**: New blocks reference the previous block's hash -3. **Chain Validation**: System verifies each block's hash matches its calculated hash AND links to previous block -4. **Data Integrity**: Changing any block invalidates all subsequent blocks +1. **Genesis Block**: Each blockchain starts with block index 0 (no mining required) +2. **Adding Blocks**: + - Client sends data and optional difficulty + - System validates input (dry-validation) + - Block is created with reference to previous block's hash + - Mining process begins (PoW algorithm) + - Block is saved once valid hash is found +3. **Mining Process**: + - System tries different nonce values + - Calculates hash for each nonce + - Continues until hash starts with required leading zeros + - Higher difficulty = more zeros = more attempts = more secure +4. **Chain Validation**: + - Verifies each block's hash matches its calculated hash + - Verifies each block's hash meets difficulty requirement (valid_hash?) + - Verifies each block links to previous block's hash + - If any check fails, chain is invalid +5. **Data Integrity**: + - Changing any block invalidates its hash + - Invalid hash breaks PoW requirement + - Breaks link to next block + - Invalidates entire chain from that point forward +6. **Security Layers**: + - **PoW**: Computationally expensive to modify blocks + - **Rate Limiting**: Prevents API abuse (Rack::Attack) + - **Input Validation**: Prevents malformed data (dry-validation) + - **Hash Chaining**: Each block depends on previous block + +### Data Flow + +``` +Client Request + ↓ +Rate Limiting (Rack::Attack) + ↓ +Input Validation (dry-validation) + ↓ +Blockchain Integrity Check + ↓ +Block Creation + ↓ +Mining (Proof of Work) + ↓ +Block Saved to MongoDB + ↓ +JSON Response +``` + +## Security + +### Rate Limiting + +Implemented via Rack::Attack middleware: +- Protects against DoS attacks +- Prevents resource exhaustion +- Per-IP address enforcement +- Configurable limits per endpoint +- Disabled in test environment + +### Input Validation + +Implemented via dry-validation: +- Type checking (strings, integers) +- Range validation (difficulty 1-10) +- Required field enforcement +- Returns detailed error messages +- Prevents injection attacks + +### Cryptographic Security + +- SHA256 hashing for block integrity +- Proof of Work for block creation +- Immutable chain structure +- Hash-based tamper detection + +### Known Limitations + +This is an educational project and lacks production-grade security: +- ❌ No encryption for data at rest +- ❌ No authentication/authorization +- ❌ No HTTPS enforcement +- ❌ Simple in-memory rate limiting +- ❌ No distributed consensus +- ❌ No peer-to-peer networking + +For security best practices, see [SECURITY.md](SECURITY.md). + +## Configuration + +### Environment Variables + +| Variable | Description | Default | Required | +|----------|-------------|---------|----------| +| `MONGO_DB_NAME` | MongoDB database name | chain_forge | Yes | +| `MONGO_DB_HOST` | MongoDB hostname | localhost | Yes | +| `MONGO_DB_PORT` | MongoDB port | 27017 | Yes | +| `ENVIRONMENT` | Runtime environment | development | Yes | +| `DEFAULT_DIFFICULTY` | Default mining difficulty (1-10) | 2 | No | + +### Docker Environment + +When using Docker Compose, environment variables are configured automatically. Override in `docker-compose.yml` if needed. + +### Test Environment + +Test configuration is in `.env.test`: +- Uses separate database: `chain_forge_test` +- Rate limiting disabled +- Coverage reporting enabled with `COVERAGE=true` ## Contributing -This is a personal learning project, but suggestions and improvements are welcome! Feel free to open an issue or PR. +Contributions are welcome! This is a learning project focused on understanding blockchain fundamentals. + +For contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md). + +### Development Guidelines + +- Maintain educational value (readable, well-commented code) +- Include RSpec tests for all features (aim for >90% coverage) +- Follow RuboCop style guidelines +- Update documentation when adding features +- All PRs must pass CI checks + +## Documentation + +- [API_DOCUMENTATION.md](API_DOCUMENTATION.md) - Complete API reference +- [SECURITY.md](SECURITY.md) - Security policies and best practices +- [CONTRIBUTING.md](CONTRIBUTING.md) - Contribution guidelines +- [DEPLOYMENT.md](DEPLOYMENT.md) - Production deployment guide +- [CHANGELOG.md](CHANGELOG.md) - Version history +- [CLAUDE.md](CLAUDE.md) - Claude Code guidance ## License @@ -141,4 +488,22 @@ MIT License - see LICENSE file for details ## Acknowledgments -Built as a learning exercise to understand blockchain technology fundamentals. +Built as a learning exercise to understand blockchain technology fundamentals, including: +- Cryptographic hashing (SHA256) +- Proof of Work consensus +- Chain integrity validation +- API security best practices +- RESTful API design + +Special thanks to the blockchain community for educational resources and inspiration. + +## Version History + +See [CHANGELOG.md](CHANGELOG.md) for detailed version history. + +**Current Version**: 2.0.0 +- ✅ Proof of Work mining +- ✅ API versioning +- ✅ Rate limiting and validation +- ✅ Environment configuration +- ✅ CI/CD pipeline diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..7dbb8b5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,315 @@ +# Security Policy + +## Overview + +ChainForge is an **educational project** NOT intended for production use. It demonstrates blockchain security concepts but lacks production-grade security features. + +## Security Features + +### Rate Limiting + +API endpoints are protected by Rack::Attack: + +| Scope | Limit | Window | Action | +|-------|-------|--------|--------| +| All endpoints | 60 requests | 1 minute | 429 response | +| POST /api/v1/chain | 10 requests | 1 minute | 429 response | +| POST /api/v1/chain/:id/block | 30 requests | 1 minute | 429 response | + +**Limitations:** +- Memory-based (resets on restart) +- Per-IP enforcement only +- Not suitable for distributed systems +- Can be bypassed with multiple IPs + +### Input Validation + +All API inputs validated via dry-validation: + +**Validated Fields:** +- `data`: Must be non-empty string +- `difficulty`: Must be integer 1-10 + +**Protection Against:** +- Type confusion attacks +- Invalid data injection +- Out-of-range values + +**Error Response (400):** +```json +{ + "errors": { + "data": ["must be filled"], + "difficulty": ["must be between 1 and 10"] + } +} +``` + +### Cryptographic Security + +**Block Integrity:** +- SHA256 hashing (256-bit security) +- Proof of Work verification +- Hash chaining (immutability) + +**Proof of Work:** +- Computational cost to modify blocks +- Difficulty-based security level +- Prevents easy chain tampering + +**Limitations:** +- Single SHA256 (Bitcoin uses double) +- Fixed difficulty (no dynamic adjustment) +- No distributed consensus + +## Known Vulnerabilities + +### Authentication & Authorization +**Issue:** No authentication system +**Impact:** Anyone can use API +**Risk:** High +**Mitigation:** Use only in trusted environments + +### Data Encryption +**Issue:** No encryption at rest or in transit +**Impact:** Data visible in MongoDB and network +**Risk:** High +**Mitigation:** Never store sensitive data + +### HTTPS +**Issue:** No TLS/SSL enforcement +**Impact:** Man-in-the-middle attacks possible +**Risk:** High +**Mitigation:** Run behind HTTPS proxy in production + +### MongoDB Security +**Issue:** No authentication configured +**Impact:** Database accessible without credentials +**Risk:** High +**Mitigation:** Configure MongoDB authentication in production + +### Denial of Service +**Issue:** Simple in-memory rate limiting +**Impact:** Can be exhausted with multiple IPs +**Risk:** Medium +**Mitigation:** Use Redis-backed rate limiting in production + +### Code Injection +**Issue:** No sanitization beyond type checking +**Impact:** Potentially malicious data stored +**Risk:** Low (stored, not executed) +**Mitigation:** Validate data content, not just type + +## Reporting Vulnerabilities + +### Security Issues + +If you discover a security vulnerability: + +**DO NOT** open a public GitHub issue + +Instead: +1. Email: [your-email@example.com] +2. Include: + - Description of vulnerability + - Steps to reproduce + - Potential impact + - Suggested fix (if known) + +### Response Timeline + +- **Acknowledgment**: Within 48 hours +- **Assessment**: Within 1 week +- **Fix**: Depends on severity +- **Disclosure**: After fix is deployed + +### Severity Levels + +**Critical**: Remote code execution, data breach +- Response: Immediate (same day) + +**High**: Authentication bypass, DoS +- Response: 1-3 days + +**Medium**: Information disclosure +- Response: 1-2 weeks + +**Low**: Minor issues +- Response: Best effort + +## Security Best Practices + +### Development + +```bash +# Never commit sensitive data +git add .env # ❌ Wrong +git add .env.example # ✅ Correct + +# Use environment variables +difficulty = 2 # ❌ Wrong +difficulty = ENV.fetch('DEFAULT_DIFFICULTY', '2').to_i # ✅ Correct + +# Validate all inputs +data = params[:data] # ❌ Wrong +validation = BlockDataContract.new.call(params) # ✅ Correct +``` + +### Deployment + +**Never expose to public internet without:** +- ✅ Reverse proxy with HTTPS +- ✅ MongoDB authentication +- ✅ Firewall rules +- ✅ Rate limiting (Redis-backed) +- ✅ Authentication system +- ✅ Input sanitization +- ✅ Monitoring and logging + +### MongoDB Security + +```yaml +# docker-compose.yml (production) +mongodb: + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD} + volumes: + - mongodb_data:/data/db + networks: + - internal # Not exposed to public +``` + +### Reverse Proxy (nginx) + +```nginx +server { + listen 443 ssl; + server_name api.example.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + + location /api/ { + proxy_pass http://localhost:1910; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # Rate limiting + limit_req zone=api burst=10 nodelay; + } +} +``` + +## Out of Scope + +The following are known educational limitations and NOT security bugs: + +- No peer-to-peer networking +- No distributed consensus +- No transaction signing +- No authentication/authorization +- No HTTPS enforcement +- Simple rate limiting +- No encryption at rest +- No input sanitization beyond type checking +- No SQL injection protection (using MongoDB) +- No XSS protection (API only, no web interface) + +## Security Checklist + +### Before Deploying + +- [ ] Configure MongoDB authentication +- [ ] Set up HTTPS with valid certificates +- [ ] Implement reverse proxy (nginx/apache) +- [ ] Configure firewall rules +- [ ] Use Redis-backed rate limiting +- [ ] Set strong DEFAULT_DIFFICULTY (4+) +- [ ] Enable logging and monitoring +- [ ] Never store sensitive data +- [ ] Implement authentication +- [ ] Regular security updates (`bundle update`) + +### Monitoring + +Monitor for: +- Unusual traffic patterns +- Rate limit violations +- Mining attempts with high difficulty +- Database connection errors +- Authentication failures (if implemented) + +## Compliance + +### GDPR / Privacy + +ChainForge stores: +- IP addresses (rate limiting) +- User-provided data in blocks +- Timestamps + +**Recommendations:** +- Don't store personal data +- Implement data deletion +- Add privacy policy +- Obtain user consent + +### Data Retention + +- Blockchain data is immutable +- Cannot delete blocks once created +- Consider implications before storing data + +## Security Resources + +### Learning + +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [Ruby on Rails Security Guide](https://guides.rubyonrails.org/security.html) +- [MongoDB Security Checklist](https://docs.mongodb.com/manual/administration/security-checklist/) + +### Tools + +- **bundler-audit**: Check for vulnerable gems +- **brakeman**: Static security analysis (Rails) +- **RuboCop**: Security cops +- **OWASP ZAP**: Penetration testing + +### Commands + +```bash +# Check for vulnerable dependencies +gem install bundler-audit +bundle audit check --update + +# Security-focused linting +bundle exec rubocop --only Security +``` + +## Educational Context + +ChainForge demonstrates blockchain security concepts: + +**✅ What it teaches:** +- Cryptographic hashing +- Proof of Work security +- Chain immutability +- Rate limiting basics +- Input validation + +**❌ What it doesn't cover:** +- Distributed consensus security +- Cryptographic key management +- Network security +- Advanced DoS protection +- Data encryption + +Use this project to learn fundamentals, then study production systems (Bitcoin, Ethereum) for comprehensive security. + +## Updates + +This security policy is reviewed and updated with each major release. + +**Last Updated:** 2025-11-09 +**Version:** 2.0.0