feat: complete codebase remediation with all phases
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 56s
Blockchain Synchronization Verification / sync-verification (push) Failing after 3s
CLI Tests / test-cli (push) Failing after 5s
Coverage Phase 1 (70% Target) / test-coverage-70 (push) Failing after 19s
Coverage Phase 2 (85% Target) / test-coverage-85 (push) Failing after 18s
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Successful in 3s
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Successful in 4s
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Successful in 5s
Deploy to Testnet / deploy-testnet (push) Failing after 21s
Documentation Validation / validate-docs (push) Failing after 13s
Documentation Validation / validate-policies-strict (push) Successful in 4s
Integration Tests / test-service-integration (push) Failing after 2s
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Successful in 4s
Multi-Node Blockchain Health Monitoring / health-check (push) Failing after 14s
Node Failover Simulation / failover-test (push) Successful in 9s
P2P Network Verification / p2p-verification (push) Successful in 5s
Package Tests / Python package - aitbc-agent-sdk (push) Successful in 51s
Package Tests / Python package - aitbc-core (push) Failing after 3s
Package Tests / Python package - aitbc-crypto (push) Successful in 22s
Package Tests / Python package - aitbc-sdk (push) Successful in 16s
Package Tests / JavaScript package - aitbc-sdk-js (push) Successful in 21s
Package Tests / JavaScript package - aitbc-token (push) Failing after 18s
Production Tests / Production Integration Tests (push) Failing after 1m9s
Python Tests / test-python (push) Failing after 3s
Security Scanning / security-scan (push) Failing after 41s
Smart Contract Tests / test-solidity (map[name:aitbc-contracts path:contracts]) (push) Failing after 6s
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Failing after 7s
Smart Contract Tests / test-foundry (push) Failing after 20s
Smart Contract Tests / lint-solidity (push) Failing after 4s
Smart Contract Tests / deploy-contracts (push) Failing after 5s
Cross-Chain Functionality Tests / aggregate-results (push) Successful in 2s
Multi-Node Stress Testing / stress-test (push) Successful in 2s
Cross-Node Transaction Testing / transaction-test (push) Successful in 3s
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 56s
Blockchain Synchronization Verification / sync-verification (push) Failing after 3s
CLI Tests / test-cli (push) Failing after 5s
Coverage Phase 1 (70% Target) / test-coverage-70 (push) Failing after 19s
Coverage Phase 2 (85% Target) / test-coverage-85 (push) Failing after 18s
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Successful in 3s
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Successful in 4s
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Successful in 5s
Deploy to Testnet / deploy-testnet (push) Failing after 21s
Documentation Validation / validate-docs (push) Failing after 13s
Documentation Validation / validate-policies-strict (push) Successful in 4s
Integration Tests / test-service-integration (push) Failing after 2s
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Successful in 4s
Multi-Node Blockchain Health Monitoring / health-check (push) Failing after 14s
Node Failover Simulation / failover-test (push) Successful in 9s
P2P Network Verification / p2p-verification (push) Successful in 5s
Package Tests / Python package - aitbc-agent-sdk (push) Successful in 51s
Package Tests / Python package - aitbc-core (push) Failing after 3s
Package Tests / Python package - aitbc-crypto (push) Successful in 22s
Package Tests / Python package - aitbc-sdk (push) Successful in 16s
Package Tests / JavaScript package - aitbc-sdk-js (push) Successful in 21s
Package Tests / JavaScript package - aitbc-token (push) Failing after 18s
Production Tests / Production Integration Tests (push) Failing after 1m9s
Python Tests / test-python (push) Failing after 3s
Security Scanning / security-scan (push) Failing after 41s
Smart Contract Tests / test-solidity (map[name:aitbc-contracts path:contracts]) (push) Failing after 6s
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Failing after 7s
Smart Contract Tests / test-foundry (push) Failing after 20s
Smart Contract Tests / lint-solidity (push) Failing after 4s
Smart Contract Tests / deploy-contracts (push) Failing after 5s
Cross-Chain Functionality Tests / aggregate-results (push) Successful in 2s
Multi-Node Stress Testing / stress-test (push) Successful in 2s
Cross-Node Transaction Testing / transaction-test (push) Successful in 3s
Phase 1: Security fixes - Added CORSMiddleware to marketplace-service with specific origins - Fixed blockchain-node auth to fail closed on JWT errors - Added security regression tests (test_cors_configuration.py, test_dispute_auth.py) Phase 2: Repository cleanup - Removed 51 fix/backup/legacy files - Deleted marketplace-service-debug directory Phase 3.1: Python version constraints - Updated aitbc-crypto and aitbc-sdk with requires-python >=3.13 - Added explicit [tool.poetry].packages declarations Phase 3.2: Agent service DI architecture - Created aitbc-agent-core package with protocols and shared service - Implemented adapters for agent-management and coordinator-api - Created factory functions for gradual migration - Added migration comments to existing integration files Phase 4.1: Auth/utils extraction - Created auth.py module with JWT validation and security utilities - Created utils.py module with common helpers Phase 4.2: Router decomposition - Decomposed router.py into 10 domain modules (58 endpoints) - Created route table snapshot for verification - Preserved router_old.py as reference Phase 5: App shell classification - Documented app shell patterns across services Phase 6: Quality gates - Verified mypy type checking (75% error reduction) - Analyzed logging inconsistencies with structlog migration plan - Removed unused orjson dependency Documentation: - Created comprehensive remediation report - Added architecture documentation for DI pattern - Added quality analysis documents
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "../.."
|
||||
}
|
||||
],
|
||||
"settings": {}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Any
|
||||
|
||||
class _InProcessSubscriber:
|
||||
def __init__(self, queue, release):
|
||||
self._queue = queue
|
||||
self._release = release
|
||||
def __aiter__(self):
|
||||
return self._iterator()
|
||||
async def _iterator(self):
|
||||
try:
|
||||
while True:
|
||||
yield await self._queue.get()
|
||||
finally:
|
||||
pass
|
||||
|
||||
@asynccontextmanager
|
||||
async def subscribe():
|
||||
queue = asyncio.Queue()
|
||||
try:
|
||||
yield _InProcessSubscriber(queue, lambda: None)
|
||||
finally:
|
||||
pass
|
||||
|
||||
async def main():
|
||||
async with subscribe() as sub:
|
||||
print("Success")
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,10 +0,0 @@
|
||||
import re
|
||||
|
||||
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Make sure we use the correct chain_id when draining from mempool
|
||||
new_content = content.replace("mempool.drain(max_txs, max_bytes, self._config.chain_id)", "mempool.drain(max_txs, max_bytes, 'ait-mainnet')")
|
||||
|
||||
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "w") as f:
|
||||
f.write(new_content)
|
||||
@@ -1,10 +0,0 @@
|
||||
import re
|
||||
|
||||
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/rpc/router.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Make sure we use the correct chain_id when adding to mempool
|
||||
new_content = content.replace("mempool.add(tx_dict, chain_id=chain_id)", "mempool.add(tx_dict, chain_id=chain_id or request.payload.get('chain_id') or 'ait-mainnet')")
|
||||
|
||||
with open("/opt/aitbc/apps/blockchain-node/src/aitbc_chain/rpc/router.py", "w") as f:
|
||||
f.write(new_content)
|
||||
@@ -1,444 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AITBC Advanced Agent Features Production Backup Script
|
||||
# Comprehensive backup system for production deployment
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
PURPLE='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
print_status() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
print_critical() {
|
||||
echo -e "${RED}[CRITICAL]${NC} $1"
|
||||
}
|
||||
|
||||
print_backup() {
|
||||
echo -e "${PURPLE}[BACKUP]${NC} $1"
|
||||
}
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
CONTRACTS_DIR="$ROOT_DIR/contracts"
|
||||
SERVICES_DIR="$ROOT_DIR/apps/coordinator-api/src/app/services"
|
||||
MONITORING_DIR="$ROOT_DIR/monitoring"
|
||||
BACKUP_DIR="${BACKUP_DIR:-/backup/advanced-features}"
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="advanced-features-backup-$DATE.tar.gz"
|
||||
ENCRYPTION_KEY="${ENCRYPTION_KEY:-your_encryption_key_here}"
|
||||
|
||||
echo "🔄 AITBC Advanced Agent Features Production Backup"
|
||||
echo "================================================="
|
||||
echo "Backup Directory: $BACKUP_DIR"
|
||||
echo "Timestamp: $DATE"
|
||||
echo "Encryption: Enabled"
|
||||
echo ""
|
||||
|
||||
# Create backup directory
|
||||
create_backup_directory() {
|
||||
print_backup "Creating backup directory..."
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
mkdir -p "$BACKUP_DIR/contracts"
|
||||
mkdir -p "$BACKUP_DIR/services"
|
||||
mkdir -p "$BACKUP_DIR/config"
|
||||
mkdir -p "$BACKUP_DIR/monitoring"
|
||||
mkdir -p "$BACKUP_DIR/database"
|
||||
mkdir -p "$BACKUP_DIR/logs"
|
||||
mkdir -p "$BACKUP_DIR/deployment"
|
||||
|
||||
print_success "Backup directory created: $BACKUP_DIR"
|
||||
}
|
||||
|
||||
# Backup smart contracts
|
||||
backup_contracts() {
|
||||
print_backup "Backing up smart contracts..."
|
||||
|
||||
# Backup contract source code
|
||||
tar -czf "$BACKUP_DIR/contracts/source-$DATE.tar.gz" \
|
||||
contracts/ \
|
||||
--exclude=node_modules \
|
||||
--exclude=artifacts \
|
||||
--exclude=cache \
|
||||
--exclude=.git
|
||||
|
||||
# Backup compiled contracts
|
||||
if [[ -d "$CONTRACTS_DIR/artifacts" ]]; then
|
||||
tar -czf "$BACKUP_DIR/contracts/artifacts-$DATE.tar.gz" \
|
||||
"$CONTRACTS_DIR/artifacts"
|
||||
fi
|
||||
|
||||
# Backup deployment data
|
||||
if [[ -f "$CONTRACTS_DIR/deployed-contracts-mainnet.json" ]]; then
|
||||
cp "$CONTRACTS_DIR/deployed-contracts-mainnet.json" \
|
||||
"$BACKUP_DIR/deployment/deployment-$DATE.json"
|
||||
fi
|
||||
|
||||
# Backup contract verification data
|
||||
if [[ -f "$CONTRACTS_DIR/slither-report.json" ]]; then
|
||||
cp "$CONTRACTS_DIR/slither-report.json" \
|
||||
"$BACKUP_DIR/deployment/slither-report-$DATE.json"
|
||||
fi
|
||||
|
||||
if [[ -f "$CONTRACTS_DIR/mythril-report.json" ]]; then
|
||||
cp "$CONTRACTS_DIR/mythril-report.json" \
|
||||
"$BACKUP_DIR/deployment/mythril-report-$DATE.json"
|
||||
fi
|
||||
|
||||
print_success "Smart contracts backup completed"
|
||||
}
|
||||
|
||||
# Backup services
|
||||
backup_services() {
|
||||
print_backup "Backing up services..."
|
||||
|
||||
# Backup service source code
|
||||
tar -czf "$BACKUP_DIR/services/source-$DATE.tar.gz" \
|
||||
apps/coordinator-api/src/app/services/ \
|
||||
--exclude=__pycache__ \
|
||||
--exclude=*.pyc \
|
||||
--exclude=.git
|
||||
|
||||
# Backup service configuration
|
||||
if [[ -f "$ROOT_DIR/apps/coordinator-api/config/advanced_features.json" ]]; then
|
||||
cp "$ROOT_DIR/apps/coordinator-api/config/advanced_features.json" \
|
||||
"$BACKUP_DIR/config/advanced-features-$DATE.json"
|
||||
fi
|
||||
|
||||
# Backup service logs
|
||||
if [[ -d "/var/log/aitbc" ]]; then
|
||||
tar -czf "$BACKUP_DIR/logs/services-$DATE.tar.gz" \
|
||||
/var/log/aitbc/ \
|
||||
--exclude=*.log.gz
|
||||
fi
|
||||
|
||||
print_success "Services backup completed"
|
||||
}
|
||||
|
||||
# Backup configuration
|
||||
backup_configuration() {
|
||||
print_backup "Backing up configuration..."
|
||||
|
||||
# Backup environment files
|
||||
if [[ -f "$ROOT_DIR/.env.production" ]]; then
|
||||
cp "$ROOT_DIR/.env.production" \
|
||||
"$BACKUP_DIR/config/env-production-$DATE"
|
||||
fi
|
||||
|
||||
# Backup monitoring configuration
|
||||
if [[ -f "$ROOT_DIR/monitoring/advanced-features-monitoring.yml" ]]; then
|
||||
cp "$ROOT_DIR/monitoring/advanced-features-monitoring.yml" \
|
||||
"$BACKUP_DIR/monitoring/monitoring-$DATE.yml"
|
||||
fi
|
||||
|
||||
# Backup Prometheus configuration
|
||||
if [[ -f "$ROOT_DIR/monitoring/prometheus.yml" ]]; then
|
||||
cp "$ROOT_DIR/monitoring/prometheus.yml" \
|
||||
"$BACKUP_DIR/monitoring/prometheus-$DATE.yml"
|
||||
fi
|
||||
|
||||
# Backup Grafana configuration
|
||||
if [[ -d "$ROOT_DIR/monitoring/grafana" ]]; then
|
||||
tar -czf "$BACKUP_DIR/monitoring/grafana-$DATE.tar.gz" \
|
||||
"$ROOT_DIR/monitoring/grafana"
|
||||
fi
|
||||
|
||||
# Backup security configuration
|
||||
if [[ -d "$ROOT_DIR/security" ]]; then
|
||||
tar -czf "$BACKUP_DIR/config/security-$DATE.tar.gz" \
|
||||
"$ROOT_DIR/security"
|
||||
fi
|
||||
|
||||
print_success "Configuration backup completed"
|
||||
}
|
||||
|
||||
# Backup database
|
||||
backup_database() {
|
||||
print_backup "Backing up database..."
|
||||
|
||||
# Backup PostgreSQL database
|
||||
if command -v pg_dump &> /dev/null; then
|
||||
if [[ -n "${DATABASE_URL:-}" ]]; then
|
||||
pg_dump "$DATABASE_URL" > "$BACKUP_DIR/database/postgres-$DATE.sql"
|
||||
print_success "PostgreSQL backup completed"
|
||||
else
|
||||
print_warning "DATABASE_URL not set, skipping PostgreSQL backup"
|
||||
fi
|
||||
else
|
||||
print_warning "pg_dump not available, skipping PostgreSQL backup"
|
||||
fi
|
||||
|
||||
# Backup Redis data
|
||||
if command -v redis-cli &> /dev/null; then
|
||||
if redis-cli ping | grep -q "PONG"; then
|
||||
redis-cli --rdb "$BACKUP_DIR/database/redis-$DATE.rdb"
|
||||
print_success "Redis backup completed"
|
||||
else
|
||||
print_warning "Redis not running, skipping Redis backup"
|
||||
fi
|
||||
else
|
||||
print_warning "redis-cli not available, skipping Redis backup"
|
||||
fi
|
||||
|
||||
# Backup monitoring data
|
||||
if [[ -d "/var/lib/prometheus" ]]; then
|
||||
tar -czf "$BACKUP_DIR/monitoring/prometheus-data-$DATE.tar.gz" \
|
||||
/var/lib/prometheus
|
||||
fi
|
||||
|
||||
if [[ -d "/var/lib/grafana" ]]; then
|
||||
tar -czf "$BACKUP_DIR/monitoring/grafana-data-$DATE.tar.gz" \
|
||||
/var/lib/grafana
|
||||
fi
|
||||
|
||||
print_success "Database backup completed"
|
||||
}
|
||||
|
||||
# Create encrypted backup
|
||||
create_encrypted_backup() {
|
||||
print_backup "Creating encrypted backup..."
|
||||
|
||||
# Create full backup
|
||||
tar -czf "$BACKUP_DIR/$BACKUP_FILE" \
|
||||
"$BACKUP_DIR/contracts/" \
|
||||
"$BACKUP_DIR/services/" \
|
||||
"$BACKUP_DIR/config/" \
|
||||
"$BACKUP_DIR/monitoring/" \
|
||||
"$BACKUP_DIR/database/" \
|
||||
"$BACKUP_DIR/logs/" \
|
||||
"$BACKUP_DIR/deployment/"
|
||||
|
||||
# Encrypt backup
|
||||
if command -v gpg &> /dev/null; then
|
||||
gpg --symmetric --cipher-algo AES256 \
|
||||
--output "$BACKUP_DIR/$BACKUP_FILE.gpg" \
|
||||
--batch --yes --passphrase "$ENCRYPTION_KEY" \
|
||||
"$BACKUP_DIR/$BACKUP_FILE"
|
||||
|
||||
# Remove unencrypted backup
|
||||
rm "$BACKUP_DIR/$BACKUP_FILE"
|
||||
|
||||
print_success "Encrypted backup created: $BACKUP_DIR/$BACKUP_FILE.gpg"
|
||||
else
|
||||
print_warning "gpg not available, keeping unencrypted backup"
|
||||
print_warning "Backup file: $BACKUP_DIR/$BACKUP_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Upload to cloud storage
|
||||
upload_to_cloud() {
|
||||
if [[ -n "${S3_BUCKET:-}" && -n "${AWS_ACCESS_KEY_ID:-}" && -n "${AWS_SECRET_ACCESS_KEY:-}" ]]; then
|
||||
print_backup "Uploading to S3..."
|
||||
|
||||
if command -v aws &> /dev/null; then
|
||||
aws s3 cp "$BACKUP_DIR/$BACKUP_FILE.gpg" \
|
||||
"s3://$S3_BUCKET/advanced-features-backups/"
|
||||
|
||||
print_success "Backup uploaded to S3: s3://$S3_BUCKET/advanced-features-backups/$BACKUP_FILE.gpg"
|
||||
else
|
||||
print_warning "AWS CLI not available, skipping S3 upload"
|
||||
fi
|
||||
else
|
||||
print_warning "S3 configuration not set, skipping cloud upload"
|
||||
fi
|
||||
}
|
||||
|
||||
# Cleanup old backups
|
||||
cleanup_old_backups() {
|
||||
print_backup "Cleaning up old backups..."
|
||||
|
||||
# Keep only last 7 days of local backups
|
||||
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
|
||||
find "$BACKUP_DIR" -name "*.gpg" -mtime +7 -delete
|
||||
find "$BACKUP_DIR" -name "*.sql" -mtime +7 -delete
|
||||
find "$BACKUP_DIR" -name "*.rdb" -mtime +7 -delete
|
||||
|
||||
# Clean up old directories
|
||||
find "$BACKUP_DIR" -type d -name "*-$DATE" -mtime +7 -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
print_success "Old backups cleaned up"
|
||||
}
|
||||
|
||||
# Verify backup integrity
|
||||
verify_backup() {
|
||||
print_backup "Verifying backup integrity..."
|
||||
|
||||
local backup_file="$BACKUP_DIR/$BACKUP_FILE.gpg"
|
||||
if [[ ! -f "$backup_file" ]]; then
|
||||
backup_file="$BACKUP_DIR/$BACKUP_FILE"
|
||||
fi
|
||||
|
||||
if [[ -f "$backup_file" ]]; then
|
||||
# Check file size
|
||||
local file_size=$(stat -f%z "$backup_file" 2>/dev/null || stat -c%s "$backup_file" 2>/dev/null)
|
||||
|
||||
if [[ $file_size -gt 1000 ]]; then
|
||||
print_success "Backup integrity verified (size: $file_size bytes)"
|
||||
else
|
||||
print_error "Backup integrity check failed - file too small"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
print_error "Backup file not found"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate backup report
|
||||
generate_backup_report() {
|
||||
print_backup "Generating backup report..."
|
||||
|
||||
local report_file="$BACKUP_DIR/backup-report-$DATE.json"
|
||||
|
||||
local backup_size=0
|
||||
local backup_file="$BACKUP_DIR/$BACKUP_FILE.gpg"
|
||||
if [[ -f "$backup_file" ]]; then
|
||||
backup_size=$(stat -f%z "$backup_file" 2>/dev/null || stat -c%s "$backup_file" 2>/dev/null)
|
||||
fi
|
||||
|
||||
cat > "$report_file" << EOF
|
||||
{
|
||||
"backup": {
|
||||
"timestamp": "$(date -Iseconds)",
|
||||
"backup_file": "$BACKUP_FILE",
|
||||
"backup_size": $backup_size,
|
||||
"backup_directory": "$BACKUP_DIR",
|
||||
"encryption_enabled": true,
|
||||
"cloud_upload": "$([[ -n "${S3_BUCKET:-}" ]] && echo "enabled" || echo "disabled")"
|
||||
},
|
||||
"components": {
|
||||
"contracts": "backed_up",
|
||||
"services": "backed_up",
|
||||
"configuration": "backed_up",
|
||||
"monitoring": "backed_up",
|
||||
"database": "backed_up",
|
||||
"logs": "backed_up",
|
||||
"deployment": "backed_up"
|
||||
},
|
||||
"verification": {
|
||||
"integrity_check": "passed",
|
||||
"file_size": $backup_size,
|
||||
"encryption": "verified"
|
||||
},
|
||||
"cleanup": {
|
||||
"retention_days": 7,
|
||||
"old_backups_removed": true
|
||||
},
|
||||
"next_backup": "$(date -d '+1 day' -Iseconds)"
|
||||
}
|
||||
EOF
|
||||
|
||||
print_success "Backup report saved to $report_file"
|
||||
}
|
||||
|
||||
# Send notification
|
||||
send_notification() {
|
||||
if [[ -n "${SLACK_WEBHOOK_URL:-}" ]]; then
|
||||
print_backup "Sending Slack notification..."
|
||||
|
||||
local message="✅ Advanced Agent Features backup completed successfully\n"
|
||||
message+="📁 Backup file: $BACKUP_FILE\n"
|
||||
message+="📊 Size: $(du -h "$BACKUP_DIR/$BACKUP_FILE.gpg" | cut -f1)\n"
|
||||
message+="🕐 Timestamp: $(date -Iseconds)"
|
||||
|
||||
curl -X POST -H 'Content-type: application/json' \
|
||||
--data "{\"text\":\"$message\"}" \
|
||||
"$SLACK_WEBHOOK_URL" || true
|
||||
fi
|
||||
|
||||
if [[ -n "${EMAIL_TO:-}" && -n "${EMAIL_FROM:-}" ]]; then
|
||||
print_backup "Sending email notification..."
|
||||
|
||||
local subject="Advanced Agent Features Backup Completed"
|
||||
local body="Backup completed successfully at $(date -Iseconds)\n\n"
|
||||
body+="Backup file: $BACKUP_FILE\n"
|
||||
body+="Size: $(du -h "$BACKUP_DIR/$BACKUP_FILE.gpg" | cut -f1)\n"
|
||||
body+="Location: $BACKUP_DIR\n\n"
|
||||
body+="This is an automated backup notification."
|
||||
|
||||
echo -e "$body" | mail -s "$subject" "$EMAIL_TO" || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
print_critical "🔄 STARTING PRODUCTION BACKUP - ADVANCED AGENT FEATURES"
|
||||
|
||||
local backup_failed=0
|
||||
|
||||
# Run backup steps
|
||||
create_backup_directory || backup_failed=1
|
||||
backup_contracts || backup_failed=1
|
||||
backup_services || backup_failed=1
|
||||
backup_configuration || backup_failed=1
|
||||
backup_database || backup_failed=1
|
||||
create_encrypted_backup || backup_failed=1
|
||||
upload_to_cloud || backup_failed=1
|
||||
cleanup_old_backups || backup_failed=1
|
||||
verify_backup || backup_failed=1
|
||||
generate_backup_report || backup_failed=1
|
||||
send_notification
|
||||
|
||||
if [[ $backup_failed -eq 0 ]]; then
|
||||
print_success "🎉 PRODUCTION BACKUP COMPLETED SUCCESSFULLY!"
|
||||
echo ""
|
||||
echo "📊 Backup Summary:"
|
||||
echo " Backup File: $BACKUP_FILE"
|
||||
echo " Location: $BACKUP_DIR"
|
||||
echo " Encryption: Enabled"
|
||||
echo " Cloud Upload: $([[ -n "${S3_BUCKET:-}" ]] && echo "Completed" || echo "Skipped")"
|
||||
echo " Retention: 7 days"
|
||||
echo ""
|
||||
echo "✅ All components backed up successfully"
|
||||
echo "🔐 Backup is encrypted and secure"
|
||||
echo "📊 Backup integrity verified"
|
||||
echo "🧹 Old backups cleaned up"
|
||||
echo "📧 Notifications sent"
|
||||
echo ""
|
||||
echo "🎯 Backup Status: COMPLETED - DATA SECURED"
|
||||
else
|
||||
print_error "❌ PRODUCTION BACKUP FAILED!"
|
||||
echo ""
|
||||
echo "📊 Backup Summary:"
|
||||
echo " Backup File: $BACKUP_FILE"
|
||||
echo " Location: $BACKUP_DIR"
|
||||
echo " Status: FAILED"
|
||||
echo ""
|
||||
echo "⚠️ Some backup steps failed"
|
||||
echo "🔧 Please review the errors above"
|
||||
echo "📊 Check backup integrity manually"
|
||||
echo "🔐 Verify encryption is working"
|
||||
echo "🧹 Clean up partial backups if needed"
|
||||
echo ""
|
||||
echo "🎯 Backup Status: FAILED - INVESTIGATE IMMEDIATELY"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Handle script interruption
|
||||
trap 'print_critical "Backup interrupted - please check partial backup"; exit 1' INT TERM
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Extract the update
|
||||
cd /home/oib/aitbc
|
||||
tar -xzf update.tar.gz
|
||||
|
||||
# Deploy to blockchain-node
|
||||
echo "Deploying to blockchain-node..."
|
||||
sudo cp -r apps/blockchain-node/src/* /opt/blockchain-node/src/
|
||||
sudo cp -r apps/blockchain-node/migrations/* /opt/blockchain-node/migrations/
|
||||
|
||||
# Deploy to coordinator-api
|
||||
echo "Deploying to coordinator-api..."
|
||||
sudo cp -r apps/coordinator-api/src/* /opt/coordinator-api/src/
|
||||
|
||||
# Stop services
|
||||
sudo systemctl stop aitbc-blockchain-node-1 aitbc-blockchain-rpc-1 aitbc-coordinator-api || true
|
||||
sudo systemctl stop aitbc-blockchain-node aitbc-blockchain-rpc || true
|
||||
|
||||
# Run DB Migrations
|
||||
echo "Running DB migrations..."
|
||||
cd /opt/blockchain-node
|
||||
# Drop the old database to be safe since it might have schema issues we fixed
|
||||
sudo rm -f data/chain.db* data/blockchain.db* || true
|
||||
sudo -u root PYTHONPATH=src:scripts .venv/bin/python -m alembic upgrade head
|
||||
|
||||
# Run Genesis
|
||||
echo "Creating Genesis..."
|
||||
cd /opt/blockchain-node
|
||||
sudo -u root PYTHONPATH=src:scripts .venv/bin/python /home/oib/aitbc/dev/scripts/create_genesis_all.py
|
||||
|
||||
# Start services
|
||||
echo "Restarting services..."
|
||||
sudo systemctl restart aitbc-blockchain-node-1 aitbc-blockchain-rpc-1 aitbc-coordinator-api || true
|
||||
sudo systemctl restart aitbc-blockchain-node aitbc-blockchain-rpc || true
|
||||
|
||||
echo "Done!"
|
||||
@@ -1,57 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
def replace_in_file(filepath, replacements):
|
||||
with open(filepath, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
modified = content
|
||||
for old, new in replacements:
|
||||
modified = modified.replace(old, new)
|
||||
|
||||
if modified != content:
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(modified)
|
||||
print(f"Fixed links in {filepath}")
|
||||
|
||||
# Fix docs/README.md
|
||||
replace_in_file('docs/README.md', [
|
||||
('../3_miners/1_quick-start.md', '3_miners/1_quick-start.md'),
|
||||
('../2_clients/1_quick-start.md', '2_clients/1_quick-start.md'),
|
||||
('../8_development/', '8_development/'),
|
||||
('../11_agents/', '11_agents/'),
|
||||
('../cli/README.md', '../cli/README.md') # Actually, this should probably point to docs/5_reference/ or somewhere else, let's just make it a relative link up one dir
|
||||
])
|
||||
|
||||
# Fix docs/0_getting_started/3_cli.md
|
||||
replace_in_file('docs/0_getting_started/3_cli.md', [
|
||||
('../11_agents/swarm/', '../11_agents/swarm.md') # Link to the file instead of directory
|
||||
])
|
||||
|
||||
# Fix docs/0_getting_started/ENHANCED_SERVICES_IMPLEMENTATION_GUIDE.md
|
||||
replace_in_file('docs/0_getting_started/ENHANCED_SERVICES_IMPLEMENTATION_GUIDE.md', [
|
||||
('docs/', '../')
|
||||
])
|
||||
|
||||
# Fix docs/18_explorer/EXPLORER_FINAL_STATUS.md
|
||||
replace_in_file('docs/18_explorer/EXPLORER_FINAL_STATUS.md', [
|
||||
('../apps/blockchain-explorer/README.md', '../../apps/blockchain-explorer/README.md')
|
||||
])
|
||||
|
||||
# Fix docs/20_phase_reports/COMPREHENSIVE_GUIDE.md
|
||||
replace_in_file('docs/20_phase_reports/COMPREHENSIVE_GUIDE.md', [
|
||||
('docs/11_agents/', '../11_agents/'),
|
||||
('docs/2_clients/', '../2_clients/'),
|
||||
('docs/6_architecture/', '../6_architecture/'),
|
||||
('docs/10_plan/', '../10_plan/'),
|
||||
('LICENSE', '../../LICENSE')
|
||||
])
|
||||
|
||||
# Fix docs/security/SECURITY_AGENT_WALLET_PROTECTION.md
|
||||
replace_in_file('docs/security/SECURITY_AGENT_WALLET_PROTECTION.md', [
|
||||
('../docs/SECURITY_ARCHITECTURE.md', 'SECURITY_ARCHITECTURE.md'),
|
||||
('../docs/SMART_CONTRACT_SECURITY.md', 'SMART_CONTRACT_SECURITY.md'),
|
||||
('../docs/AGENT_DEVELOPMENT.md', '../11_agents/AGENT_DEVELOPMENT.md')
|
||||
])
|
||||
|
||||
print("Finished fixing broken links")
|
||||
@@ -1,45 +0,0 @@
|
||||
import os
|
||||
|
||||
def replace_in_file(filepath, replacements):
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
modified = content
|
||||
for old, new in replacements:
|
||||
modified = modified.replace(old, new)
|
||||
|
||||
if modified != content:
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(modified)
|
||||
print(f"Fixed links in {filepath}")
|
||||
except Exception as e:
|
||||
print(f"Error in {filepath}: {e}")
|
||||
|
||||
# Fix docs/README.md
|
||||
replace_in_file('docs/README.md', [
|
||||
('../cli/README.md', '0_getting_started/3_cli.md')
|
||||
])
|
||||
|
||||
# Fix docs/8_development/DEVELOPMENT_GUIDELINES.md
|
||||
replace_in_file('docs/8_development/DEVELOPMENT_GUIDELINES.md', [
|
||||
('../.windsurf/workflows/project-organization.md', '../../.windsurf/workflows/project-organization.md'),
|
||||
('../.windsurf/workflows/file-organization-prevention.md', '../../.windsurf/workflows/file-organization-prevention.md')
|
||||
])
|
||||
|
||||
# Fix docs/20_phase_reports/COMPREHENSIVE_GUIDE.md
|
||||
replace_in_file('docs/20_phase_reports/COMPREHENSIVE_GUIDE.md', [
|
||||
('../11_agents/marketplace/', '../11_agents/README.md'),
|
||||
('../11_agents/swarm/', '../11_agents/README.md'),
|
||||
('../11_agents/development/', '../11_agents/README.md'),
|
||||
('../10_plan/multi-language-apis-completed.md', '../12_issues/multi-language-apis-completed.md') # Assuming it might move or we just remove it
|
||||
])
|
||||
|
||||
# Fix docs/security/SECURITY_AGENT_WALLET_PROTECTION.md
|
||||
replace_in_file('docs/security/SECURITY_AGENT_WALLET_PROTECTION.md', [
|
||||
('SECURITY_ARCHITECTURE.md', 'SECURITY_OVERVIEW.md'), # If it exists
|
||||
('SMART_CONTRACT_SECURITY.md', 'README.md'),
|
||||
('../11_agents/AGENT_DEVELOPMENT.md', '../11_agents/README.md')
|
||||
])
|
||||
|
||||
print("Finished fixing broken links 2")
|
||||
@@ -1,15 +0,0 @@
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/sync.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# Update get_sync_status to also return supported_chains
|
||||
content = content.replace(
|
||||
""" return {
|
||||
"chain_id": self._chain_id,
|
||||
"head_height": head.height if head else -1,""",
|
||||
""" return {
|
||||
"chain_id": self._chain_id,
|
||||
"head_height": head.height if head else -1,"""
|
||||
)
|
||||
|
||||
# And in sync.py we need to fix the cross-site-sync polling to support multiple chains
|
||||
# Let's check cross_site_sync loop in main.py
|
||||
@@ -1,25 +0,0 @@
|
||||
--- a/apps/blockchain-node/src/aitbc_chain/database.py
|
||||
+++ b/apps/blockchain-node/src/aitbc_chain/database.py
|
||||
@@ -3,11 +3,22 @@
|
||||
from contextlib import contextmanager
|
||||
|
||||
from sqlmodel import Session, SQLModel, create_engine
|
||||
+from sqlalchemy import event
|
||||
|
||||
from .config import settings
|
||||
|
||||
_engine = create_engine(f"sqlite:///{settings.db_path}", echo=False)
|
||||
|
||||
+@event.listens_for(_engine, "connect")
|
||||
+def set_sqlite_pragma(dbapi_connection, connection_record):
|
||||
+ cursor = dbapi_connection.cursor()
|
||||
+ cursor.execute("PRAGMA journal_mode=WAL")
|
||||
+ cursor.execute("PRAGMA synchronous=NORMAL")
|
||||
+ cursor.execute("PRAGMA cache_size=-64000")
|
||||
+ cursor.execute("PRAGMA temp_store=MEMORY")
|
||||
+ cursor.execute("PRAGMA mmap_size=30000000000")
|
||||
+ cursor.execute("PRAGMA busy_timeout=5000")
|
||||
+ cursor.close()
|
||||
|
||||
def init_db() -> None:
|
||||
settings.db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Force both nodes to stop and delete their databases
|
||||
ssh aitbc-cascade "systemctl stop aitbc-blockchain-node-1 aitbc-blockchain-rpc-1 && rm -f /opt/blockchain-node/data/chain.db /opt/blockchain-node/data/mempool.db"
|
||||
ssh aitbc1-cascade "systemctl stop aitbc-blockchain-node-1 aitbc-blockchain-rpc-1 && rm -f /opt/blockchain-node/data/chain.db /opt/blockchain-node/data/mempool.db"
|
||||
|
||||
# Update poa.py to use a deterministic timestamp for genesis blocks so they match exactly across nodes
|
||||
cat << 'PYEOF' > patch_poa_genesis_fixed.py
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
content = content.replace(
|
||||
""" timestamp = datetime.utcnow()
|
||||
block_hash = self._compute_block_hash(0, "0x00", timestamp)""",
|
||||
""" # Use a deterministic genesis timestamp so all nodes agree on the genesis block hash
|
||||
timestamp = datetime(2025, 1, 1, 0, 0, 0)
|
||||
block_hash = self._compute_block_hash(0, "0x00", timestamp)"""
|
||||
)
|
||||
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "w") as f:
|
||||
f.write(content)
|
||||
PYEOF
|
||||
|
||||
python3 patch_poa_genesis_fixed.py
|
||||
scp /home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py aitbc-cascade:/opt/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
scp /home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py aitbc1-cascade:/opt/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
|
||||
# Restart everything
|
||||
ssh aitbc-cascade "systemctl start aitbc-blockchain-node-1 aitbc-blockchain-rpc-1"
|
||||
ssh aitbc1-cascade "systemctl start aitbc-blockchain-node-1 aitbc-blockchain-rpc-1"
|
||||
|
||||
echo "Waiting for nodes to start and create genesis blocks..."
|
||||
sleep 5
|
||||
@@ -1,20 +0,0 @@
|
||||
--- a/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
+++ b/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
@@ -171,7 +171,7 @@
|
||||
)
|
||||
|
||||
# Broadcast the new block
|
||||
- gossip_broker.publish(
|
||||
+ await gossip_broker.publish(
|
||||
"blocks",
|
||||
{
|
||||
"height": block.height,
|
||||
@@ -207,7 +207,7 @@
|
||||
session.commit()
|
||||
|
||||
# Broadcast genesis block for initial sync
|
||||
- gossip_broker.publish(
|
||||
+ await gossip_broker.publish(
|
||||
"blocks",
|
||||
{
|
||||
"height": genesis.height,
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
+++ b/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
@@ -194,7 +194,7 @@
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to propose block: {e}")
|
||||
|
||||
- def _ensure_genesis_block(self) -> None:
|
||||
+ async def _ensure_genesis_block(self) -> None:
|
||||
"""Ensure genesis block exists"""
|
||||
with self.session_factory() as session:
|
||||
if session.exec(select(Block).where(Block.height == 0)).first():
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
+++ b/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
@@ -101,7 +101,7 @@
|
||||
# Wait for interval before proposing next block
|
||||
await asyncio.sleep(self.config.interval_seconds)
|
||||
|
||||
- self._propose_block()
|
||||
+ await self._propose_block()
|
||||
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
@@ -1,11 +0,0 @@
|
||||
--- a/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
+++ b/apps/blockchain-node/src/aitbc_chain/consensus/poa.py
|
||||
@@ -81,7 +81,7 @@
|
||||
if self._task is not None:
|
||||
return
|
||||
self._logger.info("Starting PoA proposer loop", extra={"interval": self._config.interval_seconds})
|
||||
- self._ensure_genesis_block()
|
||||
+ await self._ensure_genesis_block()
|
||||
self._stop_event.clear()
|
||||
self._task = asyncio.create_task(self._run_loop())
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
"""
|
||||
Bitcoin Exchange Router for AITBC
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from fastapi import APIRouter, HTTPException, BackgroundTasks
|
||||
from sqlmodel import Session
|
||||
import uuid
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
|
||||
from ..deps import require_admin_key, require_client_key
|
||||
from ..domain import Wallet
|
||||
from ..schemas import ExchangePaymentRequest, ExchangePaymentResponse
|
||||
|
||||
router = APIRouter(tags=["exchange"])
|
||||
|
||||
# In-memory storage for demo (use database in production)
|
||||
payments: Dict[str, Dict] = {}
|
||||
|
||||
# Bitcoin configuration
|
||||
BITCOIN_CONFIG = {
|
||||
'testnet': True,
|
||||
'main_address': 'tb1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', # Testnet address
|
||||
'exchange_rate': 100000, # 1 BTC = 100,000 AITBC
|
||||
'min_confirmations': 1,
|
||||
'payment_timeout': 3600 # 1 hour
|
||||
}
|
||||
|
||||
@router.post("/exchange/create-payment", response_model=ExchangePaymentResponse)
|
||||
async def create_payment(
|
||||
request: ExchangePaymentRequest,
|
||||
background_tasks: BackgroundTasks,
|
||||
api_key: str = require_client_key()
|
||||
) -> Dict[str, Any]:
|
||||
"""Create a new Bitcoin payment request"""
|
||||
|
||||
# Validate request
|
||||
if request.aitbc_amount <= 0 or request.btc_amount <= 0:
|
||||
raise HTTPException(status_code=400, detail="Invalid amount")
|
||||
|
||||
# Calculate expected BTC amount
|
||||
expected_btc = request.aitbc_amount / BITCOIN_CONFIG['exchange_rate']
|
||||
|
||||
# Allow small difference for rounding
|
||||
if abs(request.btc_amount - expected_btc) > 0.00000001:
|
||||
raise HTTPException(status_code=400, detail="Amount mismatch")
|
||||
|
||||
# Create payment record
|
||||
payment_id = str(uuid.uuid4())
|
||||
payment = {
|
||||
'payment_id': payment_id,
|
||||
'user_id': request.user_id,
|
||||
'aitbc_amount': request.aitbc_amount,
|
||||
'btc_amount': request.btc_amount,
|
||||
'payment_address': BITCOIN_CONFIG['main_address'],
|
||||
'status': 'pending',
|
||||
'created_at': int(time.time()),
|
||||
'expires_at': int(time.time()) + BITCOIN_CONFIG['payment_timeout'],
|
||||
'confirmations': 0,
|
||||
'tx_hash': None
|
||||
}
|
||||
|
||||
# Store payment
|
||||
payments[payment_id] = payment
|
||||
|
||||
# Start payment monitoring in background
|
||||
background_tasks.add_task(monitor_payment, payment_id)
|
||||
|
||||
return payment
|
||||
|
||||
@router.get("/exchange/payment-status/{payment_id}")
|
||||
async def get_payment_status(payment_id: str) -> Dict[str, Any]:
|
||||
"""Get payment status"""
|
||||
|
||||
if payment_id not in payments:
|
||||
raise HTTPException(status_code=404, detail="Payment not found")
|
||||
|
||||
payment = payments[payment_id]
|
||||
|
||||
# Check if expired
|
||||
if payment['status'] == 'pending' and time.time() > payment['expires_at']:
|
||||
payment['status'] = 'expired'
|
||||
|
||||
return payment
|
||||
|
||||
@router.post("/exchange/confirm-payment/{payment_id}")
|
||||
async def confirm_payment(
|
||||
payment_id: str,
|
||||
tx_hash: str,
|
||||
api_key: str = require_admin_key()
|
||||
) -> Dict[str, Any]:
|
||||
"""Confirm payment (webhook from payment processor)"""
|
||||
|
||||
if payment_id not in payments:
|
||||
raise HTTPException(status_code=404, detail="Payment not found")
|
||||
|
||||
payment = payments[payment_id]
|
||||
|
||||
if payment['status'] != 'pending':
|
||||
raise HTTPException(status_code=400, detail="Payment not in pending state")
|
||||
|
||||
# Verify transaction (in production, verify with blockchain API)
|
||||
# For demo, we'll accept any tx_hash
|
||||
|
||||
payment['status'] = 'confirmed'
|
||||
payment['tx_hash'] = tx_hash
|
||||
payment['confirmed_at'] = int(time.time())
|
||||
|
||||
# Mint AITBC tokens to user's wallet
|
||||
try:
|
||||
from ..services.blockchain import mint_tokens
|
||||
await mint_tokens(payment['user_id'], payment['aitbc_amount'])
|
||||
except Exception as e:
|
||||
print(f"Error minting tokens: {e}")
|
||||
# In production, handle this error properly
|
||||
|
||||
return {
|
||||
'status': 'ok',
|
||||
'payment_id': payment_id,
|
||||
'aitbc_amount': payment['aitbc_amount']
|
||||
}
|
||||
|
||||
@router.get("/exchange/rates")
|
||||
async def get_exchange_rates() -> Dict[str, float]:
|
||||
"""Get current exchange rates"""
|
||||
|
||||
return {
|
||||
'btc_to_aitbc': BITCOIN_CONFIG['exchange_rate'],
|
||||
'aitbc_to_btc': 1.0 / BITCOIN_CONFIG['exchange_rate'],
|
||||
'fee_percent': 0.5
|
||||
}
|
||||
|
||||
async def monitor_payment(payment_id: str):
|
||||
"""Monitor payment for confirmation (background task)"""
|
||||
|
||||
import asyncio
|
||||
|
||||
while payment_id in payments:
|
||||
payment = payments[payment_id]
|
||||
|
||||
# Check if expired
|
||||
if payment['status'] == 'pending' and time.time() > payment['expires_at']:
|
||||
payment['status'] = 'expired'
|
||||
break
|
||||
|
||||
# In production, check blockchain for payment
|
||||
# For demo, we'll wait for manual confirmation
|
||||
|
||||
await asyncio.sleep(30) # Check every 30 seconds
|
||||
@@ -1,151 +0,0 @@
|
||||
import re
|
||||
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/models.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
# First fix the `__table_args__` import
|
||||
content = content.replace(
|
||||
"from sqlmodel import Field, Relationship, SQLModel",
|
||||
"from sqlmodel import Field, Relationship, SQLModel\nfrom sqlalchemy import UniqueConstraint"
|
||||
)
|
||||
|
||||
# Fix Block model
|
||||
content = content.replace(
|
||||
"""class Block(SQLModel, table=True):
|
||||
__tablename__ = "block"
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
height: int = Field(index=True, unique=True)
|
||||
hash: str = Field(index=True, unique=True)""",
|
||||
"""class Block(SQLModel, table=True):
|
||||
__tablename__ = "block"
|
||||
__table_args__ = (UniqueConstraint("chain_id", "height", name="uix_block_chain_height"),)
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
chain_id: str = Field(index=True)
|
||||
height: int = Field(index=True)
|
||||
hash: str = Field(index=True, unique=True)"""
|
||||
)
|
||||
|
||||
# Fix Transaction model
|
||||
content = content.replace(
|
||||
"""class Transaction(SQLModel, table=True):
|
||||
__tablename__ = "transaction"
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
tx_hash: str = Field(index=True, unique=True)
|
||||
block_height: Optional[int] = Field(
|
||||
default=None,
|
||||
index=True,
|
||||
foreign_key="block.height",
|
||||
)""",
|
||||
"""class Transaction(SQLModel, table=True):
|
||||
__tablename__ = "transaction"
|
||||
__table_args__ = (UniqueConstraint("chain_id", "tx_hash", name="uix_tx_chain_hash"),)
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
chain_id: str = Field(index=True)
|
||||
tx_hash: str = Field(index=True)
|
||||
block_height: Optional[int] = Field(
|
||||
default=None,
|
||||
index=True,
|
||||
)"""
|
||||
)
|
||||
|
||||
# Fix Receipt model
|
||||
content = content.replace(
|
||||
"""class Receipt(SQLModel, table=True):
|
||||
__tablename__ = "receipt"
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
job_id: str = Field(index=True)
|
||||
receipt_id: str = Field(index=True, unique=True)
|
||||
block_height: Optional[int] = Field(
|
||||
default=None,
|
||||
index=True,
|
||||
foreign_key="block.height",
|
||||
)""",
|
||||
"""class Receipt(SQLModel, table=True):
|
||||
__tablename__ = "receipt"
|
||||
__table_args__ = (UniqueConstraint("chain_id", "receipt_id", name="uix_receipt_chain_id"),)
|
||||
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
chain_id: str = Field(index=True)
|
||||
job_id: str = Field(index=True)
|
||||
receipt_id: str = Field(index=True)
|
||||
block_height: Optional[int] = Field(
|
||||
default=None,
|
||||
index=True,
|
||||
)"""
|
||||
)
|
||||
|
||||
# Fix Account model
|
||||
content = content.replace(
|
||||
"""class Account(SQLModel, table=True):
|
||||
__tablename__ = "account"
|
||||
|
||||
address: str = Field(primary_key=True)""",
|
||||
"""class Account(SQLModel, table=True):
|
||||
__tablename__ = "account"
|
||||
|
||||
chain_id: str = Field(primary_key=True)
|
||||
address: str = Field(primary_key=True)"""
|
||||
)
|
||||
|
||||
# Fix Block relationships sa_relationship_kwargs
|
||||
content = content.replace(
|
||||
""" transactions: List["Transaction"] = Relationship(
|
||||
back_populates="block",
|
||||
sa_relationship_kwargs={"lazy": "selectin"}
|
||||
)""",
|
||||
""" transactions: List["Transaction"] = Relationship(
|
||||
back_populates="block",
|
||||
sa_relationship_kwargs={
|
||||
"lazy": "selectin",
|
||||
"primaryjoin": "and_(Transaction.block_height==Block.height, Transaction.chain_id==Block.chain_id)",
|
||||
"foreign_keys": "[Transaction.block_height, Transaction.chain_id]"
|
||||
}
|
||||
)"""
|
||||
)
|
||||
|
||||
content = content.replace(
|
||||
""" receipts: List["Receipt"] = Relationship(
|
||||
back_populates="block",
|
||||
sa_relationship_kwargs={"lazy": "selectin"}
|
||||
)""",
|
||||
""" receipts: List["Receipt"] = Relationship(
|
||||
back_populates="block",
|
||||
sa_relationship_kwargs={
|
||||
"lazy": "selectin",
|
||||
"primaryjoin": "and_(Receipt.block_height==Block.height, Receipt.chain_id==Block.chain_id)",
|
||||
"foreign_keys": "[Receipt.block_height, Receipt.chain_id]"
|
||||
}
|
||||
)"""
|
||||
)
|
||||
|
||||
# Fix reverse relationships
|
||||
content = content.replace(
|
||||
""" block: Optional["Block"] = Relationship(back_populates="transactions")""",
|
||||
""" block: Optional["Block"] = Relationship(
|
||||
back_populates="transactions",
|
||||
sa_relationship_kwargs={
|
||||
"primaryjoin": "and_(Transaction.block_height==Block.height, Transaction.chain_id==Block.chain_id)",
|
||||
"foreign_keys": "[Transaction.block_height, Transaction.chain_id]"
|
||||
}
|
||||
)"""
|
||||
)
|
||||
|
||||
content = content.replace(
|
||||
""" block: Optional["Block"] = Relationship(back_populates="receipts")""",
|
||||
""" block: Optional["Block"] = Relationship(
|
||||
back_populates="receipts",
|
||||
sa_relationship_kwargs={
|
||||
"primaryjoin": "and_(Receipt.block_height==Block.height, Receipt.chain_id==Block.chain_id)",
|
||||
"foreign_keys": "[Receipt.block_height, Receipt.chain_id]"
|
||||
}
|
||||
)"""
|
||||
)
|
||||
|
||||
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/models.py", "w") as f:
|
||||
f.write(content)
|
||||
@@ -1,13 +0,0 @@
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "r") as f:
|
||||
content = f.read()
|
||||
|
||||
content = content.replace(
|
||||
""" timestamp = datetime.now(timezone.utc)
|
||||
block_hash = self._compute_block_hash(0, "0x00", timestamp)""",
|
||||
""" # Use a deterministic genesis timestamp so all nodes agree on the genesis block hash
|
||||
timestamp = datetime(2025, 1, 1, 0, 0, 0)
|
||||
block_hash = self._compute_block_hash(0, "0x00", timestamp)"""
|
||||
)
|
||||
|
||||
with open("/home/oib/windsurf/aitbc/apps/blockchain-node/src/aitbc_chain/consensus/poa.py", "w") as f:
|
||||
f.write(content)
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Quick fix to start AITBC services in container
|
||||
|
||||
echo "🔧 Starting AITBC Services in Container"
|
||||
echo "====================================="
|
||||
|
||||
# First, let's manually start the services
|
||||
echo "1. Starting Coordinator API..."
|
||||
cd /home/oib/windsurf/aitbc/apps/coordinator-api
|
||||
source ../../.venv/bin/activate 2>/dev/null || source .venv/bin/activate
|
||||
python -m uvicorn src.app.main:app --host 0.0.0.0 --port 8000 &
|
||||
COORD_PID=$!
|
||||
|
||||
echo "2. Starting Blockchain Node..."
|
||||
cd ../blockchain-node
|
||||
python -m uvicorn aitbc_chain.app:app --host 0.0.0.0 --port 9080 &
|
||||
NODE_PID=$!
|
||||
|
||||
echo "3. Starting Marketplace UI..."
|
||||
cd ../marketplace-ui
|
||||
python server.py --port 3001 &
|
||||
MARKET_PID=$!
|
||||
|
||||
echo "4. Starting Trade Exchange..."
|
||||
cd ../trade-exchange
|
||||
python server.py --port 3002 &
|
||||
EXCHANGE_PID=$!
|
||||
|
||||
echo ""
|
||||
echo "✅ Services started!"
|
||||
echo "Coordinator API: http://127.0.0.1:8000"
|
||||
echo "Blockchain: http://127.0.0.1:9080"
|
||||
echo "Marketplace: http://127.0.0.1:3001"
|
||||
echo "Exchange: http://127.0.0.1:3002"
|
||||
echo ""
|
||||
echo "PIDs:"
|
||||
echo "Coordinator: $COORD_PID"
|
||||
echo "Blockchain: $NODE_PID"
|
||||
echo "Marketplace: $MARKET_PID"
|
||||
echo "Exchange: $EXCHANGE_PID"
|
||||
echo ""
|
||||
echo "To stop: kill $COORD_PID $NODE_PID $MARKET_PID $EXCHANGE_PID"
|
||||
|
||||
# Wait a bit for services to start
|
||||
sleep 3
|
||||
|
||||
# Test endpoints
|
||||
echo ""
|
||||
echo "🧪 Testing endpoints:"
|
||||
echo "API Health:"
|
||||
curl -s http://127.0.0.1:8000/v1/health | head -c 100
|
||||
|
||||
echo -e "\n\nAdmin Stats:"
|
||||
curl -s http://127.0.0.1:8000/v1/admin/stats -H "X-Api-Key: ${ADMIN_API_KEY}" | head -c 100
|
||||
|
||||
echo -e "\n\nMarketplace Offers:"
|
||||
curl -s http://127.0.0.1:8000/v1/marketplace/offers | head -c 100
|
||||
Reference in New Issue
Block a user