Context Verification

Verify the authenticity and integrity of BB-MCP contexts using blockchain records. Learn how to validate contexts, check signatures, and ensure data hasn't been tampered with.

How Verification Works

BB-MCP uses cryptographic signatures and blockchain records for verification

What Gets Verified

  • Authenticity: Context came from claimed agent
  • Integrity: Data hasn't been modified
  • Timestamp: Context created at claimed time
  • Non-repudiation: Agent cannot deny creating it

Verification Levels

Full Verification
Signature + Blockchain + Hash validation
Signature Only
Cryptographic signature validation
Blockchain Only
Hash presence on blockchain

Basic Verification

Verify a context using its transaction hash or context ID

Python SDK

import bb_mcp

client = bb_mcp.Client(api_key="your_api_key")

# Method 1: Verify by transaction hash
verification = client.verify_context(
    transaction_hash="0x1a2b3c4d5e6f7890abcdef..."
)

if verification.verified:
    print("✅ Context verified successfully!")
    print(f"Agent ID: {verification.agent_id}")
    print(f"Block Number: {verification.block_number}")
    print(f"Confirmations: {verification.confirmations}")
    print(f"Verified at: {verification.block_timestamp}")
else:
    print("❌ Verification failed")
    print(f"Reason: {verification.error_reason}")

# Method 2: Verify by context ID
verification = client.verify_context(
    context_id="ctx_1234567890abcdef"
)

# Method 3: Verify with local context data
context_data = {
    "agent_id": "my-agent",
    "timestamp": "2024-01-15T10:30:00Z",
    "context_data": {"task": "classification", "result": "positive"},
    "metadata": {"version": "1.0"}
}

verification = client.verify_context(
    transaction_hash="0x1a2b3c4d5e6f7890...",
    context=context_data  # Compares local data with blockchain record
)

JavaScript SDK

import { BBMCPClient } from '@quietstack/bb-mcp';

const client = new BBMCPClient({ apiKey: 'your_api_key' });

// Method 1: Verify by transaction hash
try {
  const verification = await client.verify({
    transaction_hash: '0x1a2b3c4d5e6f7890abcdef...'
  });

  if (verification.verified) {
    console.log('✅ Context verified successfully!');
    console.log(`Agent ID: ${verification.agent_id}`);
    console.log(`Block Number: ${verification.block_number}`);
    console.log(`Confirmations: ${verification.confirmations}`);
  } else {
    console.log('❌ Verification failed');
  }
} catch (error) {
  console.error('Verification error:', error.message);
}

// Method 2: Verify with context validation
const verification = await client.verify({
  transaction_hash: '0x1a2b3c4d5e6f7890...',
  context: {
    agent_id: 'my-agent',
    timestamp: '2024-01-15T10:30:00Z',
    context_data: { task: 'classification', result: 'positive' },
    metadata: { version: '1.0' }
  }
});

// Check specific verification aspects
console.log(`Signature valid: ${verification.signature_valid}`);
console.log(`Hash matches: ${verification.hash_matches}`);
console.log(`On blockchain: ${verification.block_number > 0}`);

Batch Verification

Verify multiple contexts efficiently in a single request

Python Implementation

# Verify multiple contexts at once
transaction_hashes = [
    "0x1a2b3c4d5e6f7890...",
    "0x9876543210fedcba...",
    "0xabcdef1234567890..."
]

# Batch verify (more efficient than individual calls)
verifications = client.verify_contexts_batch(transaction_hashes)

# Process results
for i, verification in enumerate(verifications):
    tx_hash = transaction_hashes[i]
    if verification.verified:
        print(f"✅ {tx_hash[:10]}... verified (Block: {verification.block_number})")
    else:
        print(f"❌ {tx_hash[:10]}... failed ({verification.error_reason})")

# Summary statistics
total = len(verifications)
verified = sum(1 for v in verifications if v.verified)
print(f"\nVerification Summary: {verified}/{total} contexts verified ({verified/total*100:.1f}%)")

# Filter for different verification statuses
confirmed = [v for v in verifications if v.verified and v.confirmations >= 12]
pending = [v for v in verifications if v.verified and v.confirmations < 12]
failed = [v for v in verifications if not v.verified]

print(f"Confirmed: {len(confirmed)}, Pending: {len(pending)}, Failed: {len(failed)}")

JavaScript Implementation

// Verify multiple contexts concurrently
const transactionHashes = [
  '0x1a2b3c4d5e6f7890...',
  '0x9876543210fedcba...',
  '0xabcdef1234567890...'
];

// Method 1: Batch API call (recommended)
const verifications = await client.verifyBatch(transactionHashes);

// Process results
verifications.forEach((verification, index) => {
  const txHash = transactionHashes[index];
  if (verification.verified) {
    console.log(`✅ ${txHash.substring(0, 10)}... verified (Block: ${verification.block_number})`);
  } else {
    console.log(`❌ ${txHash.substring(0, 10)}... failed (${verification.error_reason})`);
  }
});

// Method 2: Concurrent individual calls
const verifyPromises = transactionHashes.map(hash => 
  client.verify({ transaction_hash: hash })
);

const results = await Promise.allSettled(verifyPromises);

// Handle mixed success/failure
results.forEach((result, index) => {
  const txHash = transactionHashes[index];
  if (result.status === 'fulfilled' && result.value.verified) {
    console.log(`✅ ${txHash.substring(0, 10)}... verified`);
  } else {
    const reason = result.status === 'rejected' 
      ? result.reason.message 
      : result.value.error_reason;
    console.log(`❌ ${txHash.substring(0, 10)}... failed: ${reason}`);
  }
});

Verification Response Format

Understanding the verification response structure

Successful Verification

{
  "verified": true,
  "transaction_hash": "0x1a2b3c4d5e6f7890abcdef123456789012345678",
  "block_number": 123456789,
  "block_timestamp": "2024-01-15T10:30:05Z",
  "confirmations": 15,
  "agent_id": "my-classification-agent",
  "context_hash": "0xabcdef1234567890fedcba0987654321abcdef12",
  "signature_valid": true,
  "hash_matches": true,
  "verification_time": "2024-01-15T11:45:23Z",
  "network": "polygon",
  "gas_used": 42000,
  "verification_details": {
    "signature_algorithm": "ECDSA",
    "hash_algorithm": "SHA-256",
    "public_key": "0x04a1b2c3d4e5f6...",
    "signature": "0x789abc..."
  }
}

Failed Verification

{
  "verified": false,
  "transaction_hash": "0x1a2b3c4d5e6f7890abcdef123456789012345678",
  "error_reason": "SIGNATURE_INVALID",
  "error_details": "Digital signature does not match expected value",
  "context_hash": "0xabcdef1234567890fedcba0987654321abcdef12",
  "signature_valid": false,
  "hash_matches": true,  // Hash found on blockchain but signature invalid
  "verification_time": "2024-01-15T11:45:23Z",
  "network": "polygon",
  "block_number": 123456789,  // May still be present if found
  "possible_causes": [
    "Context data was modified after signing",
    "Incorrect agent private key used for signing",
    "Corrupted signature during transmission"
  ]
}

Verification Status and Timing

Understanding confirmation times and blockchain finality

Confirmation Timeline

0-1 min
Transaction Pending
Submitted to mempool, waiting for inclusion
1-5 min
First Confirmation
Included in a block, basic verification possible
5-15 min
Confirmed
12+ confirmations, considered final on most networks

Network Comparison

NetworkBlock TimeSafe ConfirmationsFinality Time
Polygon~2 seconds12 blocks~30 seconds
Ethereum~12 seconds12 blocks~2.4 minutes
Arbitrum~1 second20 blocks~20 seconds
Base~2 seconds12 blocks~30 seconds

Checking Confirmation Status

# Poll for confirmation status
import time

def wait_for_confirmation(client, transaction_hash, required_confirmations=12, timeout=300):
    start_time = time.time()
    
    while time.time() - start_time < timeout:
        verification = client.verify_context(transaction_hash)
        
        if not verification.verified:
            print(f"❌ Verification failed: {verification.error_reason}")
            return False
            
        confirmations = verification.confirmations
        print(f"Confirmations: {confirmations}/{required_confirmations}")
        
        if confirmations >= required_confirmations:
            print(f"✅ Context confirmed with {confirmations} confirmations")
            return True
            
        time.sleep(10)  # Check every 10 seconds
    
    print(f"⏰ Timeout waiting for confirmations")
    return False

# Usage
result = client.contexts.create(context)
confirmed = wait_for_confirmation(client, result.transaction_hash)

if confirmed:
    print("Ready to use verified context")
else:
    print("Context not yet confirmed, but may still be valid")

Manual Verification

Verify contexts manually using blockchain explorers and cryptographic tools

Using Blockchain Explorers

Step 1: Look up Transaction
Use the transaction hash to find the transaction on a blockchain explorer
• Polygon: polygonscan.com
• Ethereum: etherscan.io
• Arbitrum: arbiscan.io
Step 2: Find Contract Event
Look for the ContextLogged event in the transaction logs
Event: ContextLogged(bytes32 indexed contextHash, string agentId, uint256 timestamp)
Step 3: Verify Hash
Compare the contextHash in the event with the hash of your context data

Cryptographic Verification

# Manual cryptographic verification
import hashlib
import json
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec

def verify_context_signature(context, signature, public_key_pem):
    """
    Manually verify a BB-MCP context signature
    """
    # 1. Serialize context (excluding signature and hash fields)
    context_for_signing = {
        "agent_id": context["agent_id"],
        "timestamp": context["timestamp"], 
        "context_data": context["context_data"],
        "metadata": context.get("metadata", {})
    }
    
    # 2. Create canonical JSON representation
    context_json = json.dumps(context_for_signing, sort_keys=True, separators=(',', ':'))
    
    # 3. Hash the context
    context_bytes = context_json.encode('utf-8')
    context_hash = hashlib.sha256(context_bytes).digest()
    
    # 4. Load public key
    public_key = serialization.load_pem_public_key(public_key_pem.encode())
    
    # 5. Verify signature
    try:
        public_key.verify(
            bytes.fromhex(signature),
            context_hash,
            ec.ECDSA(hashes.SHA256())
        )
        return True, context_hash.hex()
    except Exception as e:
        return False, str(e)

# Example usage
context = {
    "agent_id": "my-agent",
    "timestamp": "2024-01-15T10:30:00Z",
    "context_data": {"task": "test"},
    "signature": "3045022100..."
}

public_key_pem = """-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----"""

is_valid, result = verify_context_signature(context, context["signature"], public_key_pem)
print(f"Signature valid: {is_valid}")
print(f"Context hash: {result}")

Verification Best Practices

Guidelines for effective context verification

✅ Best Practices

  • Always verify contexts before trusting them
  • Check both signature and blockchain confirmation
  • Use batch verification for multiple contexts
  • Implement retry logic for pending transactions
  • Cache verification results to avoid redundant checks
  • Set appropriate confirmation requirements for your use case

⚠️ Common Pitfalls

  • Accepting contexts without verification
  • Not handling verification failures gracefully
  • Assuming immediate blockchain finality
  • Ignoring network-specific confirmation requirements
  • Not validating context structure before verification
  • Relying solely on client-side verification

Verification Tools & Resources

CLI Commands

bbmcp verify <tx_hash>
bbmcp verify-batch <file.txt>
bbmcp verify-context <context.json>