docs: add comprehensive contract testing, monitoring, and analytics workflow steps
All checks were successful
API Endpoint Tests / test-api-endpoints (push) Successful in 37s
Documentation Validation / validate-docs (push) Successful in 11s
Integration Tests / test-service-integration (push) Successful in 50s
Python Tests / test-python (push) Successful in 58s
Security Scanning / security-scan (push) Successful in 1m1s
All checks were successful
API Endpoint Tests / test-api-endpoints (push) Successful in 37s
Documentation Validation / validate-docs (push) Successful in 11s
Integration Tests / test-service-integration (push) Successful in 50s
Python Tests / test-python (push) Successful in 58s
Security Scanning / security-scan (push) Successful in 1m1s
📋 Workflow Enhancement:
• Add cross-node consensus testing with debugging reports (step 6)
• Add smart contract testing and service integration (step 7)
• Add enhanced contract and service testing with API structure validation (step 8)
• Add service health monitoring with quick, continuous, and alert modes (step 9)
• Add contract deployment and service integration testing (step 10)
• Add contract security and vulnerability testing with reports (step 11)
• Add
This commit is contained in:
@@ -0,0 +1,519 @@
|
||||
"""
|
||||
AITBC Agent Messaging Contract Implementation
|
||||
|
||||
This module implements on-chain messaging functionality for agents,
|
||||
enabling forum-like communication between autonomous agents.
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Optional, Any
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
import json
|
||||
import hashlib
|
||||
from eth_account import Account
|
||||
from eth_utils import to_checksum_address
|
||||
|
||||
class MessageType(Enum):
|
||||
"""Types of messages agents can send"""
|
||||
POST = "post"
|
||||
REPLY = "reply"
|
||||
ANNOUNCEMENT = "announcement"
|
||||
QUESTION = "question"
|
||||
ANSWER = "answer"
|
||||
MODERATION = "moderation"
|
||||
|
||||
class MessageStatus(Enum):
|
||||
"""Status of messages in the forum"""
|
||||
ACTIVE = "active"
|
||||
HIDDEN = "hidden"
|
||||
DELETED = "deleted"
|
||||
PINNED = "pinned"
|
||||
|
||||
@dataclass
|
||||
class Message:
|
||||
"""Represents a message in the agent forum"""
|
||||
message_id: str
|
||||
agent_id: str
|
||||
agent_address: str
|
||||
topic: str
|
||||
content: str
|
||||
message_type: MessageType
|
||||
timestamp: datetime
|
||||
parent_message_id: Optional[str] = None
|
||||
reply_count: int = 0
|
||||
upvotes: int = 0
|
||||
downvotes: int = 0
|
||||
status: MessageStatus = MessageStatus.ACTIVE
|
||||
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
@dataclass
|
||||
class Topic:
|
||||
"""Represents a forum topic"""
|
||||
topic_id: str
|
||||
title: str
|
||||
description: str
|
||||
creator_agent_id: str
|
||||
created_at: datetime
|
||||
message_count: int = 0
|
||||
last_activity: datetime = field(default_factory=datetime.now)
|
||||
tags: List[str] = field(default_factory=list)
|
||||
is_pinned: bool = False
|
||||
is_locked: bool = False
|
||||
|
||||
@dataclass
|
||||
class AgentReputation:
|
||||
"""Reputation system for agents"""
|
||||
agent_id: str
|
||||
message_count: int = 0
|
||||
upvotes_received: int = 0
|
||||
downvotes_received: int = 0
|
||||
reputation_score: float = 0.0
|
||||
trust_level: int = 1 # 1-5 trust levels
|
||||
is_moderator: bool = False
|
||||
is_banned: bool = False
|
||||
ban_reason: Optional[str] = None
|
||||
ban_expires: Optional[datetime] = None
|
||||
|
||||
class AgentMessagingContract:
|
||||
"""Main contract for agent messaging functionality"""
|
||||
|
||||
def __init__(self):
|
||||
self.messages: Dict[str, Message] = {}
|
||||
self.topics: Dict[str, Topic] = {}
|
||||
self.agent_reputations: Dict[str, AgentReputation] = {}
|
||||
self.moderation_log: List[Dict[str, Any]] = []
|
||||
|
||||
def create_topic(self, agent_id: str, agent_address: str, title: str,
|
||||
description: str, tags: List[str] = None) -> Dict[str, Any]:
|
||||
"""Create a new forum topic"""
|
||||
|
||||
# Check if agent is banned
|
||||
if self._is_agent_banned(agent_id):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Agent is banned from posting",
|
||||
"error_code": "AGENT_BANNED"
|
||||
}
|
||||
|
||||
# Generate topic ID
|
||||
topic_id = f"topic_{hashlib.sha256(f'{agent_id}_{title}_{datetime.now()}'.encode()).hexdigest()[:16]}"
|
||||
|
||||
# Create topic
|
||||
topic = Topic(
|
||||
topic_id=topic_id,
|
||||
title=title,
|
||||
description=description,
|
||||
creator_agent_id=agent_id,
|
||||
created_at=datetime.now(),
|
||||
tags=tags or []
|
||||
)
|
||||
|
||||
self.topics[topic_id] = topic
|
||||
|
||||
# Update agent reputation
|
||||
self._update_agent_reputation(agent_id, message_count=1)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"topic_id": topic_id,
|
||||
"topic": self._topic_to_dict(topic)
|
||||
}
|
||||
|
||||
def post_message(self, agent_id: str, agent_address: str, topic_id: str,
|
||||
content: str, message_type: str = "post",
|
||||
parent_message_id: str = None) -> Dict[str, Any]:
|
||||
"""Post a message to a forum topic"""
|
||||
|
||||
# Validate inputs
|
||||
if not self._validate_agent(agent_id, agent_address):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Invalid agent credentials",
|
||||
"error_code": "INVALID_AGENT"
|
||||
}
|
||||
|
||||
if self._is_agent_banned(agent_id):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Agent is banned from posting",
|
||||
"error_code": "AGENT_BANNED"
|
||||
}
|
||||
|
||||
if topic_id not in self.topics:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Topic not found",
|
||||
"error_code": "TOPIC_NOT_FOUND"
|
||||
}
|
||||
|
||||
if self.topics[topic_id].is_locked:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Topic is locked",
|
||||
"error_code": "TOPIC_LOCKED"
|
||||
}
|
||||
|
||||
# Validate message type
|
||||
try:
|
||||
msg_type = MessageType(message_type)
|
||||
except ValueError:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Invalid message type",
|
||||
"error_code": "INVALID_MESSAGE_TYPE"
|
||||
}
|
||||
|
||||
# Generate message ID
|
||||
message_id = f"msg_{hashlib.sha256(f'{agent_id}_{topic_id}_{content}_{datetime.now()}'.encode()).hexdigest()[:16]}"
|
||||
|
||||
# Create message
|
||||
message = Message(
|
||||
message_id=message_id,
|
||||
agent_id=agent_id,
|
||||
agent_address=agent_address,
|
||||
topic=topic_id,
|
||||
content=content,
|
||||
message_type=msg_type,
|
||||
timestamp=datetime.now(),
|
||||
parent_message_id=parent_message_id
|
||||
)
|
||||
|
||||
self.messages[message_id] = message
|
||||
|
||||
# Update topic
|
||||
self.topics[topic_id].message_count += 1
|
||||
self.topics[topic_id].last_activity = datetime.now()
|
||||
|
||||
# Update parent message if this is a reply
|
||||
if parent_message_id and parent_message_id in self.messages:
|
||||
self.messages[parent_message_id].reply_count += 1
|
||||
|
||||
# Update agent reputation
|
||||
self._update_agent_reputation(agent_id, message_count=1)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message_id": message_id,
|
||||
"message": self._message_to_dict(message)
|
||||
}
|
||||
|
||||
def get_messages(self, topic_id: str, limit: int = 50, offset: int = 0,
|
||||
sort_by: str = "timestamp") -> Dict[str, Any]:
|
||||
"""Get messages from a topic"""
|
||||
|
||||
if topic_id not in self.topics:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Topic not found",
|
||||
"error_code": "TOPIC_NOT_FOUND"
|
||||
}
|
||||
|
||||
# Get all messages for this topic
|
||||
topic_messages = [
|
||||
msg for msg in self.messages.values()
|
||||
if msg.topic == topic_id and msg.status == MessageStatus.ACTIVE
|
||||
]
|
||||
|
||||
# Sort messages
|
||||
if sort_by == "timestamp":
|
||||
topic_messages.sort(key=lambda x: x.timestamp, reverse=True)
|
||||
elif sort_by == "upvotes":
|
||||
topic_messages.sort(key=lambda x: x.upvotes, reverse=True)
|
||||
elif sort_by == "replies":
|
||||
topic_messages.sort(key=lambda x: x.reply_count, reverse=True)
|
||||
|
||||
# Apply pagination
|
||||
total_messages = len(topic_messages)
|
||||
paginated_messages = topic_messages[offset:offset + limit]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"messages": [self._message_to_dict(msg) for msg in paginated_messages],
|
||||
"total_messages": total_messages,
|
||||
"topic": self._topic_to_dict(self.topics[topic_id])
|
||||
}
|
||||
|
||||
def get_topics(self, limit: int = 50, offset: int = 0,
|
||||
sort_by: str = "last_activity") -> Dict[str, Any]:
|
||||
"""Get list of forum topics"""
|
||||
|
||||
# Sort topics
|
||||
topic_list = list(self.topics.values())
|
||||
|
||||
if sort_by == "last_activity":
|
||||
topic_list.sort(key=lambda x: x.last_activity, reverse=True)
|
||||
elif sort_by == "created_at":
|
||||
topic_list.sort(key=lambda x: x.created_at, reverse=True)
|
||||
elif sort_by == "message_count":
|
||||
topic_list.sort(key=lambda x: x.message_count, reverse=True)
|
||||
|
||||
# Apply pagination
|
||||
total_topics = len(topic_list)
|
||||
paginated_topics = topic_list[offset:offset + limit]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"topics": [self._topic_to_dict(topic) for topic in paginated_topics],
|
||||
"total_topics": total_topics
|
||||
}
|
||||
|
||||
def vote_message(self, agent_id: str, agent_address: str, message_id: str,
|
||||
vote_type: str) -> Dict[str, Any]:
|
||||
"""Vote on a message (upvote/downvote)"""
|
||||
|
||||
# Validate inputs
|
||||
if not self._validate_agent(agent_id, agent_address):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Invalid agent credentials",
|
||||
"error_code": "INVALID_AGENT"
|
||||
}
|
||||
|
||||
if message_id not in self.messages:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Message not found",
|
||||
"error_code": "MESSAGE_NOT_FOUND"
|
||||
}
|
||||
|
||||
if vote_type not in ["upvote", "downvote"]:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Invalid vote type",
|
||||
"error_code": "INVALID_VOTE_TYPE"
|
||||
}
|
||||
|
||||
message = self.messages[message_id]
|
||||
|
||||
# Update vote counts
|
||||
if vote_type == "upvote":
|
||||
message.upvotes += 1
|
||||
else:
|
||||
message.downvotes += 1
|
||||
|
||||
# Update message author reputation
|
||||
self._update_agent_reputation(
|
||||
message.agent_id,
|
||||
upvotes_received=message.upvotes,
|
||||
downvotes_received=message.downvotes
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message_id": message_id,
|
||||
"upvotes": message.upvotes,
|
||||
"downvotes": message.downvotes
|
||||
}
|
||||
|
||||
def moderate_message(self, moderator_agent_id: str, moderator_address: str,
|
||||
message_id: str, action: str, reason: str = "") -> Dict[str, Any]:
|
||||
"""Moderate a message (hide, delete, pin)"""
|
||||
|
||||
# Validate moderator
|
||||
if not self._is_moderator(moderator_agent_id):
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Insufficient permissions",
|
||||
"error_code": "INSUFFICIENT_PERMISSIONS"
|
||||
}
|
||||
|
||||
if message_id not in self.messages:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Message not found",
|
||||
"error_code": "MESSAGE_NOT_FOUND"
|
||||
}
|
||||
|
||||
message = self.messages[message_id]
|
||||
|
||||
# Apply moderation action
|
||||
if action == "hide":
|
||||
message.status = MessageStatus.HIDDEN
|
||||
elif action == "delete":
|
||||
message.status = MessageStatus.DELETED
|
||||
elif action == "pin":
|
||||
message.status = MessageStatus.PINNED
|
||||
elif action == "unpin":
|
||||
message.status = MessageStatus.ACTIVE
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Invalid moderation action",
|
||||
"error_code": "INVALID_ACTION"
|
||||
}
|
||||
|
||||
# Log moderation action
|
||||
self.moderation_log.append({
|
||||
"timestamp": datetime.now(),
|
||||
"moderator_agent_id": moderator_agent_id,
|
||||
"message_id": message_id,
|
||||
"action": action,
|
||||
"reason": reason
|
||||
})
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message_id": message_id,
|
||||
"status": message.status.value
|
||||
}
|
||||
|
||||
def get_agent_reputation(self, agent_id: str) -> Dict[str, Any]:
|
||||
"""Get an agent's reputation information"""
|
||||
|
||||
if agent_id not in self.agent_reputations:
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Agent not found",
|
||||
"error_code": "AGENT_NOT_FOUND"
|
||||
}
|
||||
|
||||
reputation = self.agent_reputations[agent_id]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"agent_id": agent_id,
|
||||
"reputation": self._reputation_to_dict(reputation)
|
||||
}
|
||||
|
||||
def search_messages(self, query: str, limit: int = 50) -> Dict[str, Any]:
|
||||
"""Search messages by content"""
|
||||
|
||||
# Simple text search (in production, use proper search engine)
|
||||
query_lower = query.lower()
|
||||
matching_messages = []
|
||||
|
||||
for message in self.messages.values():
|
||||
if (message.status == MessageStatus.ACTIVE and
|
||||
query_lower in message.content.lower()):
|
||||
matching_messages.append(message)
|
||||
|
||||
# Sort by timestamp (most recent first)
|
||||
matching_messages.sort(key=lambda x: x.timestamp, reverse=True)
|
||||
|
||||
# Limit results
|
||||
limited_messages = matching_messages[:limit]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"query": query,
|
||||
"messages": [self._message_to_dict(msg) for msg in limited_messages],
|
||||
"total_matches": len(matching_messages)
|
||||
}
|
||||
|
||||
def _validate_agent(self, agent_id: str, agent_address: str) -> bool:
|
||||
"""Validate agent credentials"""
|
||||
# In a real implementation, this would verify the agent's signature
|
||||
# For now, we'll do basic validation
|
||||
return bool(agent_id and agent_address)
|
||||
|
||||
def _is_agent_banned(self, agent_id: str) -> bool:
|
||||
"""Check if an agent is banned"""
|
||||
if agent_id not in self.agent_reputations:
|
||||
return False
|
||||
|
||||
reputation = self.agent_reputations[agent_id]
|
||||
|
||||
if reputation.is_banned:
|
||||
# Check if ban has expired
|
||||
if reputation.ban_expires and datetime.now() > reputation.ban_expires:
|
||||
reputation.is_banned = False
|
||||
reputation.ban_expires = None
|
||||
reputation.ban_reason = None
|
||||
return False
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _is_moderator(self, agent_id: str) -> bool:
|
||||
"""Check if an agent is a moderator"""
|
||||
if agent_id not in self.agent_reputations:
|
||||
return False
|
||||
|
||||
return self.agent_reputations[agent_id].is_moderator
|
||||
|
||||
def _update_agent_reputation(self, agent_id: str, message_count: int = 0,
|
||||
upvotes_received: int = 0, downvotes_received: int = 0):
|
||||
"""Update agent reputation"""
|
||||
|
||||
if agent_id not in self.agent_reputations:
|
||||
self.agent_reputations[agent_id] = AgentReputation(agent_id=agent_id)
|
||||
|
||||
reputation = self.agent_reputations[agent_id]
|
||||
|
||||
if message_count > 0:
|
||||
reputation.message_count += message_count
|
||||
|
||||
if upvotes_received > 0:
|
||||
reputation.upvotes_received += upvotes_received
|
||||
|
||||
if downvotes_received > 0:
|
||||
reputation.downvotes_received += downvotes_received
|
||||
|
||||
# Calculate reputation score
|
||||
total_votes = reputation.upvotes_received + reputation.downvotes_received
|
||||
if total_votes > 0:
|
||||
reputation.reputation_score = (reputation.upvotes_received - reputation.downvotes_received) / total_votes
|
||||
|
||||
# Update trust level based on reputation score
|
||||
if reputation.reputation_score >= 0.8:
|
||||
reputation.trust_level = 5
|
||||
elif reputation.reputation_score >= 0.6:
|
||||
reputation.trust_level = 4
|
||||
elif reputation.reputation_score >= 0.4:
|
||||
reputation.trust_level = 3
|
||||
elif reputation.reputation_score >= 0.2:
|
||||
reputation.trust_level = 2
|
||||
else:
|
||||
reputation.trust_level = 1
|
||||
|
||||
def _message_to_dict(self, message: Message) -> Dict[str, Any]:
|
||||
"""Convert message to dictionary"""
|
||||
return {
|
||||
"message_id": message.message_id,
|
||||
"agent_id": message.agent_id,
|
||||
"agent_address": message.agent_address,
|
||||
"topic": message.topic,
|
||||
"content": message.content,
|
||||
"message_type": message.message_type.value,
|
||||
"timestamp": message.timestamp.isoformat(),
|
||||
"parent_message_id": message.parent_message_id,
|
||||
"reply_count": message.reply_count,
|
||||
"upvotes": message.upvotes,
|
||||
"downvotes": message.downvotes,
|
||||
"status": message.status.value,
|
||||
"metadata": message.metadata
|
||||
}
|
||||
|
||||
def _topic_to_dict(self, topic: Topic) -> Dict[str, Any]:
|
||||
"""Convert topic to dictionary"""
|
||||
return {
|
||||
"topic_id": topic.topic_id,
|
||||
"title": topic.title,
|
||||
"description": topic.description,
|
||||
"creator_agent_id": topic.creator_agent_id,
|
||||
"created_at": topic.created_at.isoformat(),
|
||||
"message_count": topic.message_count,
|
||||
"last_activity": topic.last_activity.isoformat(),
|
||||
"tags": topic.tags,
|
||||
"is_pinned": topic.is_pinned,
|
||||
"is_locked": topic.is_locked
|
||||
}
|
||||
|
||||
def _reputation_to_dict(self, reputation: AgentReputation) -> Dict[str, Any]:
|
||||
"""Convert reputation to dictionary"""
|
||||
return {
|
||||
"agent_id": reputation.agent_id,
|
||||
"message_count": reputation.message_count,
|
||||
"upvotes_received": reputation.upvotes_received,
|
||||
"downvotes_received": reputation.downvotes_received,
|
||||
"reputation_score": reputation.reputation_score,
|
||||
"trust_level": reputation.trust_level,
|
||||
"is_moderator": reputation.is_moderator,
|
||||
"is_banned": reputation.is_banned,
|
||||
"ban_reason": reputation.ban_reason,
|
||||
"ban_expires": reputation.ban_expires.isoformat() if reputation.ban_expires else None
|
||||
}
|
||||
|
||||
# Global contract instance
|
||||
messaging_contract = AgentMessagingContract()
|
||||
11
apps/blockchain-node/src/aitbc_chain/rpc/contract_service.py
Normal file
11
apps/blockchain-node/src/aitbc_chain/rpc/contract_service.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""Contract Service Module"""
|
||||
from typing import Dict, Any
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
class ContractService:
|
||||
@staticmethod
|
||||
def list_contracts() -> Dict[str, Any]:
|
||||
return {"contracts": [{"address": "0xguardian_001", "name": "Guardian Contract", "status": "deployed", "functions": ["storeValue", "getValue", "setGuardian"]}], "total": 1}
|
||||
|
||||
contract_service = ContractService()
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user