Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions biometrics_server/golem_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,106 @@ async def fetch_all_verifications() -> list[dict]:
verifications.sort(key=lambda x: x.get('timestamp', ''), reverse=True)
return verifications

# ========= MAIN FETCH FUNCTION (like notify_golem) =========
def fetch_golem_verification(user_id: str) -> Optional[Dict[str, Any]]:
"""
Main function to fetch verification from Golem DB - similar pattern to notify_golem
This function searches for user_id annotation and returns the latest verification
"""
try:
import threading
import concurrent.futures

def run_async_in_thread():
"""Run async function in a separate thread with proper event loop handling"""
# Create a new event loop for this thread
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

try:
return loop.run_until_complete(fetch_verification_by_user_id(user_id))
finally:
loop.close()

# Run the async function in a separate thread to avoid signal issues
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(run_async_in_thread)
verification_data = future.result(timeout=30) # 30 second timeout

if verification_data:
print(f"✅ Verification found for user {user_id}")
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the configured logger instead of print for consistency and proper log handling.

Prompt for AI agents
Address the following comment on biometrics_server/golem_endpoints.py at line 380:

<comment>Use the configured logger instead of print for consistency and proper log handling.</comment>

<file context>
@@ -350,6 +350,106 @@ async def fetch_all_verifications() -&gt; list[dict]:
+            verification_data = future.result(timeout=30)  # 30 second timeout
+            
+            if verification_data:
+                print(f&quot;✅ Verification found for user {user_id}&quot;)
+                return verification_data
+            else:
</file context>
Suggested change
print(f"✅ Verification found for user {user_id}")
logger.info(f"✅ Verification found for user {user_id}")
Fix with Cubic

return verification_data
else:
print(f"❌ No verification found for user {user_id}")
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the configured logger instead of print for consistency and observability.

Prompt for AI agents
Address the following comment on biometrics_server/golem_endpoints.py at line 383:

<comment>Use the configured logger instead of print for consistency and observability.</comment>

<file context>
@@ -350,6 +350,106 @@ async def fetch_all_verifications() -&gt; list[dict]:
+                print(f&quot;✅ Verification found for user {user_id}&quot;)
+                return verification_data
+            else:
+                print(f&quot;❌ No verification found for user {user_id}&quot;)
+                return None
+            
</file context>
Suggested change
print(f"❌ No verification found for user {user_id}")
logger.info(f"❌ No verification found for user {user_id}")
Fix with Cubic

return None

except Exception as e:
print(f"❌ Failed to fetch from Golem DB: {e}")
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the error logger instead of print to capture exceptions in logs.

Prompt for AI agents
Address the following comment on biometrics_server/golem_endpoints.py at line 387:

<comment>Use the error logger instead of print to capture exceptions in logs.</comment>

<file context>
@@ -350,6 +350,106 @@ async def fetch_all_verifications() -&gt; list[dict]:
+                return None
+            
+    except Exception as e:
+        print(f&quot;❌ Failed to fetch from Golem DB: {e}&quot;)
+        return None
+
</file context>
Suggested change
print(f"❌ Failed to fetch from Golem DB: {e}")
logger.error(f"❌ Failed to fetch from Golem DB: {e}")
Fix with Cubic

return None

async def fetch_verification_by_user_id(user_id: str) -> Optional[Dict[str, Any]]:
"""Fetch verification from Golem DB by searching for user_id annotation"""
client = await get_golem_client()

# Get account address (our writer address)
writer_address = client.get_account_address()

# Get all entities owned by this account
entity_keys = await client.get_entities_of_owner(writer_address)

latest_verification = None
latest_timestamp = None

# Search through all entities for matching user_id
for entity_key in entity_keys:
try:
# Get metadata to check annotations
metadata = await client.get_entity_metadata(entity_key)

# Check if this entity matches our user_id and is a humanity verification
is_target_user = False
is_humanity_verification = False
entity_timestamp = None

for annotation in metadata.string_annotations:
if annotation.key == "user_id" and annotation.value == user_id:
is_target_user = True
elif annotation.key == "recordType" and annotation.value == "humanity_verification":
is_humanity_verification = True
elif annotation.key == "timestamp":
entity_timestamp = annotation.value

# If this matches our criteria and is newer than current latest
if is_target_user and is_humanity_verification and entity_timestamp:
if not latest_timestamp or entity_timestamp > latest_timestamp:
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comparing timestamp strings can return the wrong latest record; parse to datetime for reliable ordering.

Prompt for AI agents
Address the following comment on biometrics_server/golem_endpoints.py at line 424:

<comment>Comparing timestamp strings can return the wrong latest record; parse to datetime for reliable ordering.</comment>

<file context>
@@ -350,6 +350,106 @@ async def fetch_all_verifications() -&gt; list[dict]:
+            
+            # If this matches our criteria and is newer than current latest
+            if is_target_user and is_humanity_verification and entity_timestamp:
+                if not latest_timestamp or entity_timestamp &gt; latest_timestamp:
+                    # Get the full entity data
+                    entity_key_hex = entity_key.as_hex_string()
</file context>
Suggested change
if not latest_timestamp or entity_timestamp > latest_timestamp:
if not latest_timestamp or datetime.fromisoformat(entity_timestamp.replace('Z', '+00:00')) > datetime.fromisoformat(latest_timestamp.replace('Z', '+00:00')):
Fix with Cubic

# Get the full entity data
entity_key_hex = entity_key.as_hex_string()
storage_value = await client.get_storage_value(GenericBytes.from_hex_string(entity_key_hex))

if storage_value:
# Decode the JSON data
entity_data = json.loads(storage_value.decode('utf-8'))

# Collect all annotations
annotations = {}
for annotation in metadata.string_annotations:
annotations[annotation.key] = annotation.value

# Update latest verification
latest_verification = {
**entity_data,
'entity_key': entity_key_hex,
'annotations': annotations,
'source': 'golem_db_direct'
}
latest_timestamp = entity_timestamp

except Exception as error:
logger.warning(f"⚠️ Error processing entity {entity_key.as_hex_string()}: {error}")
continue

return latest_verification

# ========= SYNCHRONOUS WRAPPER FUNCTIONS =========
def fetch_latest_verification_sync() -> Optional[dict]:
"""
Expand Down
88 changes: 88 additions & 0 deletions biometrics_server/main_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,94 @@ async def get_verification_status(user_id: str):
logger.error(f"❌ Error getting verification status: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")

@app.get("/golem-verification/{user_id}")
async def get_golem_verification_by_user(user_id: str):
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This endpoint re-implements logic that already exists in golem_endpoints.fetch_verification_by_user_id; prefer calling the shared function to avoid duplication and divergence.

Prompt for AI agents
Address the following comment on biometrics_server/main_fastapi.py at line 597:

<comment>This endpoint re-implements logic that already exists in golem_endpoints.fetch_verification_by_user_id; prefer calling the shared function to avoid duplication and divergence.</comment>

<file context>
@@ -593,6 +593,94 @@ async def get_verification_status(user_id: str):
         raise HTTPException(status_code=500, detail=f&quot;Internal server error: {str(e)}&quot;)
 
+@app.get(&quot;/golem-verification/{user_id}&quot;)
+async def get_golem_verification_by_user(user_id: str):
+    &quot;&quot;&quot;Get verification data directly from Golem DB by searching for user_id annotation&quot;&quot;&quot;
+    try:
</file context>
Fix with Cubic

"""Get verification data directly from Golem DB by searching for user_id annotation"""
try:
from golem_endpoints import get_golem_client
from golem_base_sdk import GenericBytes
import json

logger.info(f"🔍 Searching Golem DB for user: {Fore.GREEN}{user_id}{Style.RESET_ALL}")

# Connect to Golem DB
client = await get_golem_client()
writer_address = client.get_account_address()
logger.info(f"📝 Writer address: {writer_address}")

# Get all entities owned by this account
entity_keys = await client.get_entities_of_owner(writer_address)
logger.info(f"🔍 Found {len(entity_keys)} entities owned by writer")

latest_verification = None
latest_timestamp = None

# Search through all entities for matching user_id
for entity_key in entity_keys:
try:
# Get metadata to check annotations
metadata = await client.get_entity_metadata(entity_key)

# Check if this entity matches our user_id and is a humanity verification
is_target_user = False
is_humanity_verification = False
entity_timestamp = None

for annotation in metadata.string_annotations:
if annotation.key == "user_id" and annotation.value == user_id:
is_target_user = True
elif annotation.key == "recordType" and annotation.value == "humanity_verification":
is_humanity_verification = True
elif annotation.key == "timestamp":
entity_timestamp = annotation.value
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comparing timestamp strings may select the wrong latest verification; parse to datetime for robust ordering.

Prompt for AI agents
Address the following comment on biometrics_server/main_fastapi.py at line 635:

<comment>Comparing timestamp strings may select the wrong latest verification; parse to datetime for robust ordering.</comment>

<file context>
@@ -593,6 +593,94 @@ async def get_verification_status(user_id: str):
+                    elif annotation.key == &quot;recordType&quot; and annotation.value == &quot;humanity_verification&quot;:
+                        is_humanity_verification = True
+                    elif annotation.key == &quot;timestamp&quot;:
+                        entity_timestamp = annotation.value
+                
+                # If this matches our criteria and is newer than current latest
</file context>
Fix with Cubic


# If this matches our criteria and is newer than current latest
if is_target_user and is_humanity_verification and entity_timestamp:
if not latest_timestamp or entity_timestamp > latest_timestamp:
logger.info(f"📅 Found newer verification: {entity_timestamp}")

# Get the full entity data
entity_key_hex = entity_key.as_hex_string()
storage_value = await client.get_storage_value(GenericBytes.from_hex_string(entity_key_hex))

if storage_value:
# Decode the JSON data
entity_data = json.loads(storage_value.decode('utf-8'))

# Collect all annotations
annotations = {}
for annotation in metadata.string_annotations:
annotations[annotation.key] = annotation.value

# Update latest verification
latest_verification = {
**entity_data,
'entity_key': entity_key_hex,
'annotations': annotations,
'source': 'golem_db_direct'
}
latest_timestamp = entity_timestamp

except Exception as error:
logger.warning(f"⚠️ Error processing entity {entity_key.as_hex_string()}: {error}")
continue

if latest_verification:
logger.info(f"✅ Found latest verification for user {user_id}")
return {
"status": "success",
"verification": latest_verification
}
else:
logger.warning(f"❌ No verification found for user {user_id}")
raise HTTPException(status_code=404, detail=f"No verification found for user {user_id}")

except HTTPException:
raise
except Exception as e:
logger.error(f"❌ Error fetching verification from Golem DB for user {user_id}: {e}")
raise HTTPException(status_code=500, detail=f"Failed to fetch verification for user {user_id}: {str(e)}")

@app.get("/verification-with-golem/{user_id}")
async def get_verification_with_golem_db(user_id: str):
"""Get verification data using local biometrics data enhanced with Golem DB annotations"""
Expand Down
116 changes: 23 additions & 93 deletions frontend/src/app/(app)/home/_components/verification-hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { Button } from '@/components/ui/button';
import { useToast } from "@/hooks/use-toast";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { useAccount } from 'wagmi';
import { GolemBaseClient, GenericBytes } from 'golem-base-sdk';

interface VerificationData {
verification_id: string;
Expand Down Expand Up @@ -36,109 +35,40 @@ export function VerificationHero() {
const [isLoading, setIsLoading] = useState(false);

const fetchLatestVerification = async () => {
console.log('🔥 DIRECT GOLEM DB FETCH FUNCTION CALLED - NO API CALLS!');
console.log('🔥 FETCHING FROM NEXT.JS API ROUTE - INTEGRATED SOLUTION!');
setIsLoading(true);
try {
// Use connected wallet address, fallback to hardcoded for testing
const targetUserId = address || '0x1bc868c8C92B7fD35900f6d687067748ADbd8571';

console.log('🔍 Connecting directly to Golem DB for user:', targetUserId);
console.log('🔍 Calling Next.js API route for user:', targetUserId);

// Connect directly to Golem DB
const GOLEM_DB_RPC = "https://ethwarsaw.holesky.golemdb.io/rpc";
const GOLEM_DB_WSS = "wss://ethwarsaw.holesky.golemdb.io/rpc/ws";
const PRIVATE_KEY = process.env.NEXT_PUBLIC_PRIVATE_KEY || "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"; // Default for testing
// Call local Next.js API route - no external dependencies!
const response = await fetch(`/api/verification-by-user/${targetUserId}`);

if (!PRIVATE_KEY) {
throw new Error('Private key not configured for Golem DB connection');
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API error: ${response.status} - ${errorText}`);
}

// Create Golem DB client
const client = await GolemBaseClient.create_rw_client(
GOLEM_DB_RPC,
GOLEM_DB_WSS,
PRIVATE_KEY
);
const data = await response.json();
console.log('✅ Next.js API response:', data);
Copy link

@cubic-dev-ai cubic-dev-ai bot Sep 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrestricted console logging in production may leak identifiers and clutter logs; gate these logs behind a dev check or remove them.

Prompt for AI agents
Address the following comment on frontend/src/app/(app)/home/_components/verification-hero.tsx at line 55:

<comment>Unrestricted console logging in production may leak identifiers and clutter logs; gate these logs behind a dev check or remove them.</comment>

<file context>
@@ -36,109 +35,40 @@ export function VerificationHero() {
-        PRIVATE_KEY
-      );
+      const data = await response.json();
+      console.log(&#39;✅ Next.js API response:&#39;, data);
       
-      console.log(&#39;✅ Connected to Golem DB, searching for user_id:&#39;, targetUserId);
</file context>
Fix with Cubic


console.log('✅ Connected to Golem DB, searching for user_id:', targetUserId);

// Get account address (our writer address)
const writerAddress = client.get_account_address();
console.log('📝 Writer address:', writerAddress);

// Get all entities owned by this account
const entityKeys = await client.get_entities_of_owner(writerAddress);
console.log(`🔍 Found ${entityKeys.length} entities owned by writer`);

let latestVerification: any = null;
let latestTimestamp: string | null = null;

// Search through all entities for matching user_id
for (const entityKey of entityKeys) {
try {
// Get metadata to check annotations
const metadata = await client.get_entity_metadata(entityKey);

// Check if this entity matches our user_id and is a humanity verification
let isTargetUser = false;
let isHumanityVerification = false;
let entityTimestamp: string | null = null;

for (const annotation of metadata.string_annotations) {
if (annotation.key === "user_id" && annotation.value === targetUserId) {
isTargetUser = true;
} else if (annotation.key === "recordType" && annotation.value === "humanity_verification") {
isHumanityVerification = true;
} else if (annotation.key === "timestamp") {
entityTimestamp = annotation.value;
}
}

// If this matches our criteria and is newer than current latest
if (isTargetUser && isHumanityVerification && entityTimestamp) {
if (!latestTimestamp || entityTimestamp > latestTimestamp) {
console.log(`📅 Found newer verification: ${entityTimestamp}`);

// Get the full entity data
const entityKeyHex = entityKey.as_hex_string();
const storageValue = await client.get_storage_value(GenericBytes.from_hex_string(entityKeyHex));

if (storageValue) {
// Decode the JSON data
const entityData = JSON.parse(storageValue.toString());

// Collect all annotations
const annotations: { [key: string]: string } = {};
for (const annotation of metadata.string_annotations) {
annotations[annotation.key] = annotation.value;
}

// Update latest verification
latestVerification = {
...entityData,
entity_key: entityKeyHex,
annotations: annotations,
source: 'golem_db_direct'
};
latestTimestamp = entityTimestamp;
}
}
}
} catch (error) {
console.warn(`⚠️ Error processing entity ${entityKey.as_hex_string()}:`, error);
continue;
}
}

if (latestVerification) {
console.log('✅ Found latest verification:', latestVerification);
setVerificationData(latestVerification);
if (data.status === 'success' && data.verification) {
setVerificationData(data.verification);
console.log('✅ Successfully loaded verification data from integrated API');
console.log('📊 Verification details:');
console.log(' Entity Key:', data.verification.entity_key);
console.log(' User ID:', data.verification.user_id);
console.log(' Humanity Score:', data.verification.humanity_score);
console.log(' Timestamp:', data.verification.timestamp);
console.log(' Source:', data.verification.source);
} else {
throw new Error(`No verification found for user ${targetUserId}`);
throw new Error('Invalid response format from API');
}

} catch (error) {
console.error('❌ Error fetching verification from Golem DB:', error);
console.error('❌ Error fetching verification:', error);
toast({
title: "Error",
description: `Failed to fetch verification data: ${error instanceof Error ? error.message : 'Unknown error'}`,
Expand Down Expand Up @@ -190,14 +120,14 @@ export function VerificationHero() {
<Dialog open={isProofModalOpen} onOpenChange={setProofModalOpen}>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>🔗 Direct Golem DB Verification</DialogTitle>
<DialogDescription>Real-time data: Connected directly to Golem DB blockchain, searching by user_id annotation for latest verification with full metadata</DialogDescription>
<DialogTitle>🔗 Golem DB Verification</DialogTitle>
<DialogDescription>Real-time data: Fetched directly from Golem DB via integrated Next.js API route, showing latest verification with full blockchain metadata and annotations</DialogDescription>
</DialogHeader>
<div className="py-4 space-y-4">
{isLoading ? (
<div className="flex items-center justify-center py-8">
<Loader2 className="h-8 w-8 animate-spin" />
<span className="ml-2">Connecting directly to Golem DB blockchain...</span>
<span className="ml-2">Fetching verification data from Golem DB...</span>
</div>
) : verificationData ? (
<>
Expand Down
Loading