Skip to content

Commit b405f5c

Browse files
Update README and configuration for new tech stack
Revise the README.md to reflect changes in the storage solution to PostgreSQL and the introduction of FastAPI for the backend and React for the frontend. Adjust the project structure accordingly and update the Docker configuration for the new services. Clean up code formatting across various files for consistency.
1 parent a8d9358 commit b405f5c

10 files changed

+371
-125
lines changed

README.md

+22-12
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@ A modern, Python-based blockchain implementation focusing on simplicity, securit
2828

2929
- **Language**: Python 3.13+
3030
- **Cryptography**: `ecdsa`, `hashlib`
31-
- **Storage**: File-based (to be upgraded to LevelDB)
31+
- **Storage**: PostgreSQL for block explorer and indexing
32+
- **Backend**: FastAPI for REST API endpoints
33+
- **Frontend**: React 19 with TypeScript
3234
- **Future Stack**:
33-
- FastAPI for REST API
34-
- SQLAlchemy for database management
3535
- WebSocket for real-time updates
36-
- Vue.js for block explorer frontend
36+
- Redis for caching
37+
- Elasticsearch for block/transaction search (optional)
3738

3839
## 🏗 Project Structure
3940

@@ -45,13 +46,22 @@ ravenchain/
4546
│ ├── blockchain.py # Main blockchain logic
4647
│ ├── transaction.py # Transaction handling
4748
│ └── wallet.py # Wallet management
48-
├── config/ # Configuration
49-
│ └── settings.py # Global settings
50-
├── tests/ # Test suite
51-
├── utils/ # Utility functions
52-
├── scripts/ # Maintenance scripts
53-
├── requirements.txt # Dependencies
54-
└── README.md # Documentation
49+
├── api/ # FastAPI backend
50+
│ ├── __init__.py
51+
│ ├── main.py # API entry point
52+
│ ├── routes/ # API routes
53+
│ └── models/ # Pydantic models
54+
├── frontend/ # React 19 frontend
55+
│ ├── src/
56+
│ ├── public/
57+
│ ├── package.json
58+
│ └── tsconfig.json
59+
├── config/ # Configuration
60+
│ └── settings.py # Global settings
61+
├── tests/ # Test suite
62+
├── utils/ # Utility functions
63+
├── docker-compose.yml # Docker configuration
64+
└── README.md # Documentation
5565
```
5666

5767
## 🚀 Quick Start
@@ -124,7 +134,7 @@ docker-compose run --rm ravenchain pytest --cov=ravenchain
124134
- [ ] Documentation improvements
125135

126136
### Phase 2: Data Persistence & API (Next)
127-
- [ ] Implement LevelDB for blockchain storage
137+
- [ ] Implement PostgreSQL for blockchain storage
128138
- [ ] Design and implement FastAPI REST API
129139
- [ ] Block endpoints
130140
- [ ] Transaction endpoints

config/logging.py

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import os
2+
import sys
3+
import json
4+
import logging
5+
import logging.handlers
6+
from pathlib import Path
7+
from typing import Any, Dict
8+
9+
# Get the base directory for logs
10+
LOGS_DIR = Path(os.getenv("RAVENCHAIN_LOGS_DIR", "logs"))
11+
LOGS_DIR.mkdir(parents=True, exist_ok=True)
12+
13+
# Log file paths
14+
MAIN_LOG = LOGS_DIR / "ravenchain.log"
15+
ERROR_LOG = LOGS_DIR / "error.log"
16+
DEBUG_LOG = LOGS_DIR / "debug.log"
17+
18+
19+
class JSONFormatter(logging.Formatter):
20+
"""
21+
Formatter that outputs JSON strings after gathering all the log record args
22+
"""
23+
24+
def __init__(self, **kwargs: Any) -> None:
25+
self.default_fields = kwargs
26+
super().__init__()
27+
28+
def format(self, record: logging.LogRecord) -> str:
29+
message = {
30+
"timestamp": self.formatTime(record),
31+
"level": record.levelname,
32+
"message": record.getMessage(),
33+
"module": record.module,
34+
"function": record.funcName,
35+
"line": record.lineno,
36+
}
37+
38+
# Add extra fields from record
39+
if hasattr(record, "props"):
40+
message.update(record.props)
41+
42+
# Add default fields
43+
if self.default_fields:
44+
message.update(self.default_fields)
45+
46+
if record.exc_info:
47+
message["exc_info"] = self.formatException(record.exc_info)
48+
49+
return json.dumps(message)
50+
51+
52+
class StructuredLogger(logging.Logger):
53+
"""
54+
Custom logger class that allows structured logging with additional properties
55+
"""
56+
57+
def _log(
58+
self,
59+
level: int,
60+
msg: str,
61+
args: tuple,
62+
exc_info: Any = None,
63+
extra: Dict = None,
64+
stack_info: bool = False,
65+
**kwargs: Any,
66+
) -> None:
67+
if extra is None:
68+
extra = {}
69+
if kwargs:
70+
extra["props"] = kwargs
71+
super()._log(level, msg, args, exc_info, extra, stack_info)
72+
73+
74+
def setup_logging(
75+
service_name: str = "ravenchain",
76+
log_level: str = None,
77+
json_output: bool = False,
78+
console_output: bool = True,
79+
) -> logging.Logger:
80+
"""
81+
Set up logging configuration
82+
83+
Args:
84+
service_name: Name of the service (default: 'ravenchain')
85+
log_level: Override default log level from environment
86+
json_output: Whether to output logs in JSON format
87+
console_output: Whether to output logs to console
88+
"""
89+
# Register our custom logger class
90+
logging.setLoggerClass(StructuredLogger)
91+
92+
# Determine log level from environment or parameter
93+
log_level = log_level or os.getenv("LOG_LEVEL", "INFO")
94+
numeric_level = getattr(logging, log_level.upper(), logging.INFO)
95+
96+
# Create logger
97+
logger = logging.getLogger(service_name)
98+
logger.setLevel(numeric_level)
99+
logger.handlers = [] # Reset handlers if they exist
100+
101+
# Formatter
102+
if json_output:
103+
formatter = JSONFormatter(service=service_name)
104+
else:
105+
formatter = logging.Formatter(
106+
"%(asctime)s - %(name)s - %(levelname)s - %(module)s:%(funcName)s:%(lineno)d - %(message)s"
107+
)
108+
109+
# Console handler
110+
if console_output:
111+
console_handler = logging.StreamHandler(sys.stdout)
112+
console_handler.setFormatter(formatter)
113+
logger.addHandler(console_handler)
114+
115+
# Main rotating file handler
116+
main_handler = logging.handlers.RotatingFileHandler(
117+
MAIN_LOG, maxBytes=10 * 1024 * 1024, backupCount=5 # 10MB
118+
)
119+
main_handler.setFormatter(formatter)
120+
logger.addHandler(main_handler)
121+
122+
# Error file handler
123+
error_handler = logging.handlers.RotatingFileHandler(
124+
ERROR_LOG, maxBytes=10 * 1024 * 1024, backupCount=5 # 10MB
125+
)
126+
error_handler.setLevel(logging.ERROR)
127+
error_handler.setFormatter(formatter)
128+
logger.addHandler(error_handler)
129+
130+
# Debug file handler (only active if debug level is set)
131+
if numeric_level <= logging.DEBUG:
132+
debug_handler = logging.handlers.RotatingFileHandler(
133+
DEBUG_LOG, maxBytes=10 * 1024 * 1024, backupCount=5 # 10MB
134+
)
135+
debug_handler.setLevel(logging.DEBUG)
136+
debug_handler.setFormatter(formatter)
137+
logger.addHandler(debug_handler)
138+
139+
return logger
140+
141+
142+
# Example usage:
143+
# logger = setup_logging('ravenchain.cli', json_output=True)
144+
# logger.info("Starting application", version="1.0.0", env="production")
145+
# logger.error("Database connection failed", db_host="localhost", retry_count=3)

config/settings.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# Blockchain configuration
22
MINING_DIFFICULTY = 4
33
MINING_REWARD = 10.0
4-
BLOCK_TIME_TARGET = (
5-
600 # Target time between blocks in seconds (10 minutes like Bitcoin)
6-
)
4+
BLOCK_TIME_TARGET = 600 # Target time between blocks in seconds (10 minutes like Bitcoin)
75

86
# Network configuration
97
NODE_PORT = 5000

docker-compose.yml

+79-14
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,109 @@
1-
version: '3.8'
2-
31
services:
42
ravenchain:
53
build: .
64
volumes:
75
- .:/app
8-
ports:
9-
- "8000:8000" # For REST API
6+
- blockchain_data:/app/data
7+
- logs:/app/logs
108
environment:
119
- ENVIRONMENT=development
1210
- DEBUG=1
11+
- RAVENCHAIN_DATA_DIR=/app/data
12+
- RAVENCHAIN_LOGS_DIR=/app/logs
13+
- MINING_DIFFICULTY=2
14+
- LOG_LEVEL=DEBUG
15+
- LOG_JSON=1
1316
command: python main.py
17+
tty: true # Allocate a pseudo-TTY
18+
stdin_open: true # Keep STDIN open
1419
restart: unless-stopped
1520

16-
# Uncomment when implementing REST API
21+
# FastAPI Backend (Uncomment when ready)
1722
# api:
18-
# build: .
23+
# build:
24+
# context: .
25+
# dockerfile: Dockerfile
26+
# target: api # Using multi-stage build for API
1927
# volumes:
2028
# - .:/app
29+
# - logs:/app/logs
2130
# ports:
22-
# - "8001:8000"
31+
# - "8000:8000"
2332
# environment:
2433
# - ENVIRONMENT=development
2534
# - DEBUG=1
26-
# command: uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload
35+
# - DATABASE_URL=postgresql://ravenchain:ravenchain@db:5432/ravenchain
36+
# - RAVENCHAIN_LOGS_DIR=/app/logs
37+
# - LOG_LEVEL=DEBUG
38+
# - LOG_JSON=1
39+
# - CORS_ORIGINS=http://localhost:3000 # Allow frontend in dev
40+
# - MAX_WORKERS=4 # Uvicorn workers
41+
# command: uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload --workers 4
42+
# healthcheck:
43+
# test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
44+
# interval: 30s
45+
# timeout: 10s
46+
# retries: 3
47+
# depends_on:
48+
# db:
49+
# condition: service_healthy
50+
# ravenchain:
51+
# condition: service_started
52+
53+
# React 19 Frontend (Uncomment when ready)
54+
# frontend:
55+
# build:
56+
# context: ./frontend
57+
# dockerfile: Dockerfile.frontend
58+
# target: development # Using multi-stage build for frontend
59+
# volumes:
60+
# - ./frontend:/app
61+
# - /app/node_modules
62+
# ports:
63+
# - "3000:3000"
64+
# environment:
65+
# - NODE_ENV=development
66+
# - VITE_API_URL=http://localhost:8000 # Using Vite for React 19
67+
# - WATCHPACK_POLLING=true # Better hot reload in Docker
68+
# - VITE_BLOCKCHAIN_WS=ws://localhost:8000/ws # WebSocket for real-time updates
69+
# - VITE_ENABLE_DEVTOOLS=true # React DevTools
70+
# command: npm run dev
71+
# healthcheck:
72+
# test: ["CMD", "curl", "-f", "http://localhost:3000"]
73+
# interval: 30s
74+
# timeout: 10s
75+
# retries: 3
2776
# depends_on:
28-
# - ravenchain
77+
# api:
78+
# condition: service_healthy
2979

30-
# Uncomment when adding database
80+
# PostgreSQL 17 Database (Uncomment when ready)
3181
# db:
32-
# image: postgres:15-alpine
82+
# image: postgres:17-alpine
3383
# volumes:
3484
# - postgres_data:/var/lib/postgresql/data/
85+
# - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro # Initial schema
3586
# environment:
3687
# - POSTGRES_USER=ravenchain
3788
# - POSTGRES_PASSWORD=ravenchain
3889
# - POSTGRES_DB=ravenchain
90+
# - PGDATA=/var/lib/postgresql/data/pgdata # Custom data directory
3991
# ports:
4092
# - "5432:5432"
93+
# healthcheck:
94+
# test: ["CMD-SHELL", "pg_isready -U ravenchain"]
95+
# interval: 5s
96+
# timeout: 5s
97+
# retries: 5
98+
# command: >
99+
# postgres
100+
# -c shared_buffers=256MB
101+
# -c max_connections=200
102+
# -c effective_cache_size=1GB
103+
# -c work_mem=16MB
104+
# shm_size: '256mb' # Shared memory size for better performance
41105

42-
# Uncomment when adding database
43-
# volumes:
44-
# postgres_data:
106+
volumes:
107+
blockchain_data:
108+
logs:
109+
# postgres_data: # Uncomment when adding database

0 commit comments

Comments
 (0)