UNPKG

defarm-sdk

Version:

DeFarm SDK - On-premise blockchain data processing and tokenization engine for agriculture supply chain

266 lines (229 loc) 7.7 kB
/** * Verification Engine - Wrapper for WASM-protected business logic * This engine integrates with the WASM processor for duplicate detection and validation */ class VerificationEngine { constructor(config = {}) { this.config = { duplicateThreshold: config.duplicateThreshold || 0.85, strictMode: config.strictMode !== false, organizationId: config.organizationId, ...config }; // Load WASM processor if available this.wasmProcessor = null; this.loadWasmProcessor(); } async loadWasmProcessor() { try { this.wasmProcessor = require('../../pkg/defarm_processor.js'); console.log('✅ WASM verification engine loaded'); } catch (error) { console.warn('⚠️ WASM processor not available, using fallback'); } } /** * Check for duplicates using WASM-protected algorithms */ async checkDuplicates(newAsset, existingAssets = []) { if (!this.wasmProcessor || !this.wasmProcessor.detect_duplicates) { return this.fallbackDuplicateCheck(newAsset, existingAssets); } try { // Prepare data for WASM const newAssetJson = JSON.stringify(this.prepareAssetForWasm(newAsset)); const existingAssetsJson = JSON.stringify( existingAssets.map(a => this.prepareAssetForWasm(a)) ); // Call WASM function - algorithms are protected const resultJson = this.wasmProcessor.detect_duplicates( newAssetJson, existingAssetsJson ); const result = JSON.parse(resultJson); if (result.error) { throw new Error(result.error); } return { isDuplicate: result.has_exact_match, hasPotentialDuplicate: result.has_potential_match, exactMatches: result.exact_matches || [], potentialMatches: result.potential_matches || [], confidence: result.exact_matches?.[0]?.confidence || 0 }; } catch (error) { console.error('WASM duplicate check failed:', error); return this.fallbackDuplicateCheck(newAsset, existingAssets); } } /** * Calculate similarity between two assets */ async calculateSimilarity(asset1, asset2) { if (!this.wasmProcessor || !this.wasmProcessor.calculate_similarity) { return 0; } try { const asset1Json = JSON.stringify(this.prepareAssetForWasm(asset1)); const asset2Json = JSON.stringify(this.prepareAssetForWasm(asset2)); const similarity = this.wasmProcessor.calculate_similarity(asset1Json, asset2Json); return similarity; } catch (error) { console.error('WASM similarity calculation failed:', error); return 0; } } /** * Validate SISBOV (Brazilian livestock tracking) */ validateSisbov(sisbov) { if (!this.wasmProcessor || !this.wasmProcessor.validate_sisbov) { // Basic fallback validation return /^\d{15}$/.test(sisbov); } try { return this.wasmProcessor.validate_sisbov(sisbov); } catch (error) { console.error('SISBOV validation failed:', error); return false; } } /** * Validate asset data */ async validateAsset(assetData) { const errors = []; const warnings = []; // Basic validation if (!assetData.asset_type) { errors.push('Asset type is required'); } // Use WASM for advanced validation if available if (this.wasmProcessor && this.wasmProcessor.validate_agriculture_data) { try { const validationResult = this.wasmProcessor.validate_agriculture_data( JSON.stringify(assetData) ); const result = JSON.parse(validationResult); if (!result.valid) { errors.push(...(result.errors || [])); } warnings.push(...(result.warnings || [])); } catch (error) { warnings.push('Advanced validation unavailable'); } } // Livestock-specific validation if (assetData.asset_type === 'livestock') { if (!assetData.breed) { warnings.push('Breed information recommended for livestock'); } if (assetData.identification && assetData.identification.sisbov) { if (!this.validateSisbov(assetData.identification.sisbov)) { errors.push('Invalid SISBOV number'); } } if (assetData.birth_date) { const birthDate = new Date(assetData.birth_date); const now = new Date(); if (birthDate > now) { errors.push('Birth date cannot be in the future'); } } } // Location validation if (assetData.location) { if (!assetData.location.latitude || !assetData.location.longitude) { warnings.push('GPS coordinates recommended for traceability'); } } return { valid: errors.length === 0, errors, warnings, score: this.calculateQualityScore(assetData, errors, warnings) }; } /** * Prepare asset data for WASM processing */ prepareAssetForWasm(asset) { return { asset_id: asset.asset_id || asset.id, identification: asset.identification?.value || asset.identification, rfid: asset.rfid || asset.identification?.rfid, ear_tag: asset.ear_tag || asset.identification?.ear_tag, breed: asset.breed, location: asset.location ? { property_id: asset.location.property_id || asset.location.farm_id || 'unknown', municipality: asset.location.municipality || asset.location.city || 'unknown', state: asset.location.state || 'unknown', country: asset.location.country || 'Brazil' } : null, timestamp: asset.timestamp || asset.created_at || Date.now(), organization_id: asset.organization_id || this.config.organizationId }; } /** * Fallback duplicate check when WASM is not available */ fallbackDuplicateCheck(newAsset, existingAssets) { // Simple fallback - check exact ID matches only const exactMatches = existingAssets.filter(existing => { if (newAsset.asset_id && existing.asset_id === newAsset.asset_id) { return true; } if (newAsset.rfid && existing.rfid === newAsset.rfid) { return true; } if (newAsset.identification && existing.identification === newAsset.identification) { return true; } return false; }); return { isDuplicate: exactMatches.length > 0, hasPotentialDuplicate: false, exactMatches: exactMatches.map(a => ({ asset_id: a.asset_id, confidence: 1.0 })), potentialMatches: [], confidence: exactMatches.length > 0 ? 1.0 : 0 }; } /** * Calculate quality score for asset data */ calculateQualityScore(assetData, errors, warnings) { let score = 100; // Deduct for errors score -= errors.length * 20; // Deduct for warnings score -= warnings.length * 5; // Bonus for complete data const requiredFields = ['asset_type', 'location', 'timestamp']; const providedFields = requiredFields.filter(f => assetData[f]); score += (providedFields.length / requiredFields.length) * 10; // Bonus for certifications if (assetData.certifications && assetData.certifications.length > 0) { score += 10; } // Bonus for sustainability metrics if (assetData.metrics && assetData.metrics.sustainability_index) { score += 5; } return Math.max(0, Math.min(100, score)); } /** * Get verification statistics */ getStats() { return { wasmAvailable: !!this.wasmProcessor, strictMode: this.config.strictMode, duplicateThreshold: this.config.duplicateThreshold }; } } module.exports = { VerificationEngine };