This commit implements a complete blockchain-based plant tracking system that preserves lineage across clones, seeds, and all plant offspring while connecting growers through geographic proximity. Features implemented: - Custom blockchain with proof-of-work consensus - Plant registration and cloning with lineage tracking - Geographic discovery to find nearby plants and growers - Integration with plants.net API for plant identification - Comprehensive web UI for plant management - RESTful API endpoints for all operations - Network statistics and visualization Core Components: - lib/blockchain/: PlantBlock, PlantChain, and blockchain manager - lib/services/: plants.net API and geolocation services - pages/api/plants/: REST API endpoints for all operations - pages/: Frontend UI pages for registration, exploration, and lineage Technical Details: - TypeScript for type safety - Next.js for server-side rendering - Tailwind CSS for responsive design - JSON file-based blockchain storage - Haversine distance calculations for geolocation - OpenStreetMap integration for geocoding This system enables large-scale adoption by: - Making plant lineage tracking accessible to everyone - Connecting local communities through plant sharing - Providing immutable proof of plant provenance - Supporting unlimited generations of plant propagation - Scaling from individual growers to global networks Documentation includes comprehensive README with: - Quick start guide - API reference - Architecture details - Scaling recommendations - Use cases for various audiences - Roadmap for future enhancements
106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
/**
|
|
* Blockchain Manager
|
|
* Singleton to manage the global plant blockchain instance
|
|
*/
|
|
|
|
import { PlantChain } from './PlantChain';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
|
|
const BLOCKCHAIN_FILE = path.join(process.cwd(), 'data', 'plantchain.json');
|
|
|
|
class BlockchainManager {
|
|
private static instance: BlockchainManager;
|
|
private plantChain: PlantChain;
|
|
private autoSaveInterval: NodeJS.Timeout | null = null;
|
|
|
|
private constructor() {
|
|
this.plantChain = this.loadBlockchain();
|
|
this.startAutoSave();
|
|
}
|
|
|
|
public static getInstance(): BlockchainManager {
|
|
if (!BlockchainManager.instance) {
|
|
BlockchainManager.instance = new BlockchainManager();
|
|
}
|
|
return BlockchainManager.instance;
|
|
}
|
|
|
|
public getChain(): PlantChain {
|
|
return this.plantChain;
|
|
}
|
|
|
|
/**
|
|
* Load blockchain from file or create new one
|
|
*/
|
|
private loadBlockchain(): PlantChain {
|
|
try {
|
|
// Ensure data directory exists
|
|
const dataDir = path.join(process.cwd(), 'data');
|
|
if (!fs.existsSync(dataDir)) {
|
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
}
|
|
|
|
if (fs.existsSync(BLOCKCHAIN_FILE)) {
|
|
const data = fs.readFileSync(BLOCKCHAIN_FILE, 'utf-8');
|
|
const chainData = JSON.parse(data);
|
|
console.log('✓ Loaded existing blockchain with', chainData.chain.length, 'blocks');
|
|
return PlantChain.fromJSON(chainData);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading blockchain:', error);
|
|
}
|
|
|
|
console.log('✓ Created new blockchain');
|
|
return new PlantChain(4); // difficulty of 4
|
|
}
|
|
|
|
/**
|
|
* Save blockchain to file
|
|
*/
|
|
public saveBlockchain(): void {
|
|
try {
|
|
const dataDir = path.join(process.cwd(), 'data');
|
|
if (!fs.existsSync(dataDir)) {
|
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
}
|
|
|
|
const data = JSON.stringify(this.plantChain.toJSON(), null, 2);
|
|
fs.writeFileSync(BLOCKCHAIN_FILE, data, 'utf-8');
|
|
console.log('✓ Blockchain saved');
|
|
} catch (error) {
|
|
console.error('Error saving blockchain:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Auto-save blockchain every 5 minutes
|
|
*/
|
|
private startAutoSave(): void {
|
|
if (this.autoSaveInterval) {
|
|
clearInterval(this.autoSaveInterval);
|
|
}
|
|
|
|
this.autoSaveInterval = setInterval(() => {
|
|
this.saveBlockchain();
|
|
}, 5 * 60 * 1000); // 5 minutes
|
|
}
|
|
|
|
/**
|
|
* Stop auto-save
|
|
*/
|
|
public stopAutoSave(): void {
|
|
if (this.autoSaveInterval) {
|
|
clearInterval(this.autoSaveInterval);
|
|
this.autoSaveInterval = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function getBlockchain(): PlantChain {
|
|
return BlockchainManager.getInstance().getChain();
|
|
}
|
|
|
|
export function saveBlockchain(): void {
|
|
BlockchainManager.getInstance().saveBlockchain();
|
|
}
|