ValidatorNetwork

Description:

Governance contract for decentralized decision-making.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/ValidatorNetwork.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
 * @title ValidatorNetwork
 * @dev Decentralized validator network with Byzantine fault tolerance for Shuka
 * @notice Implements multi-validator consensus for trust verification
 */
contract ValidatorNetwork {
    
    // Validator states
    enum ValidatorStatus { INACTIVE, ACTIVE, SUSPENDED, SLASHED }
    
    // Consensus proposal states
    enum ProposalStatus { PENDING, APPROVED, REJECTED, EXECUTED, EXPIRED }
    
    // Validator information
    struct Validator {
        address validatorAddress;
        uint256 stakedAmount;
        uint256 reputationScore;
        ValidatorStatus status;
        uint256 totalValidations;
        uint256 successfulValidations;
        uint256 failedValidations;
        uint256 lastActiveBlock;
        uint256 slashingEvents;
        bool isAIAgent;
        string aiAgentId;
        uint256 joinedAt;
    }
    
    // Consensus proposal for validation
    struct ConsensusProposal {
        uint256 proposalId;
        address proposer;
        bytes32 dataHash;
        string proposalType;
        bytes proposalData;
        uint256 votesFor;
        uint256 votesAgainst;
        uint256 totalVotes;
        mapping(address => bool) hasVoted;
        mapping(address => bool) voteValue;
        ProposalStatus status;
        uint256 createdAt;
        uint256 executedAt;
        uint256 expiresAt;
    }
    
    // AI Agent validation record
    struct AIValidation {
        string agentId;
        address agentWallet;
        bytes32 validationHash;
        uint256 confidence;
        string validationType;
        uint256 timestamp;
        bool isValid;
    }
    
    // Constants for Byzantine fault tolerance
    uint256 public constant MINIMUM_VALIDATORS = 3;
    uint256 public constant BYZANTINE_THRESHOLD = 67; // 67% for Byzantine fault tolerance
    uint256 public constant MINIMUM_STAKE = 0.01 ether;
    uint256 public constant SLASHING_PENALTY = 10; // 10% of stake
    uint256 public constant PROPOSAL_DURATION = 1 hours;
    uint256 public constant VALIDATOR_TIMEOUT = 7 days;
    
    // State variables
    address public admin;
    address public trustOracleAddress;
    address public proofRegistryAddress;
    
    mapping(address => Validator) public validators;
    mapping(uint256 => ConsensusProposal) public proposals;
    mapping(string => AIValidation[]) public aiValidations;
    mapping(address => uint256) public pendingRewards;
    mapping(bytes32 => bool) public processedValidations;
    
    address[] public activeValidatorList;
    uint256 public proposalCounter;
    uint256 public totalStaked;
    uint256 public totalValidations;
    uint256 public rewardPool;
    
    // Events
    event ValidatorJoined(address indexed validator, uint256 stake, bool isAI);
    event ValidatorExited(address indexed validator, uint256 returnedStake);
    event ValidatorSlashed(address indexed validator, uint256 penalty, string reason);
    event ProposalCreated(uint256 indexed proposalId, address proposer, string proposalType);
    event VoteCast(uint256 indexed proposalId, address voter, bool support);
    event ProposalExecuted(uint256 indexed proposalId, bool approved);
    event ValidationRecorded(bytes32 validationHash, address validator, bool result);
    event RewardDistributed(address indexed validator, uint256 amount);
    event AIValidationRecorded(string agentId, bytes32 validationHash, uint256 confidence);
    
    // Modifiers
    modifier onlyAdmin() {
        require(msg.sender == admin, "Only admin");
        _;
    }
    
    modifier onlyActiveValidator() {
        require(validators[msg.sender].status == ValidatorStatus.ACTIVE, "Not active validator");
        _;
    }
    
    modifier validatorExists(address _validator) {
        require(validators[_validator].validatorAddress != address(0), "Validator not found");
        _;
    }
    
    constructor(address _trustOracle, address _proofRegistry) {
        admin = msg.sender;
        trustOracleAddress = _trustOracle;
        proofRegistryAddress = _proofRegistry;
    }
    
    /**
     * @dev Join as a validator by staking ETH
     * @param _isAIAgent Whether this is an AI agent validator
     * @param _aiAgentId ID of the AI agent (if applicable)
     */
    function joinAsValidator(bool _isAIAgent, string memory _aiAgentId) external payable {
        require(msg.value >= MINIMUM_STAKE, "Insufficient stake");
        require(validators[msg.sender].validatorAddress == address(0), "Already a validator");
        
        validators[msg.sender] = Validator({
            validatorAddress: msg.sender,
            stakedAmount: msg.value,
            reputationScore: 100,
            status: ValidatorStatus.ACTIVE,
            totalValidations: 0,
            successfulValidations: 0,
            failedValidations: 0,
            lastActiveBlock: block.number,
            slashingEvents: 0,
            isAIAgent: _isAIAgent,
            aiAgentId: _aiAgentId,
            joinedAt: block.timestamp
        });
        
        activeValidatorList.push(msg.sender);
        totalStaked += msg.value;
        
        emit ValidatorJoined(msg.sender, msg.value, _isAIAgent);
    }
    
    /**
     * @dev Create a consensus proposal for validation
     * @param _dataHash Hash of the data to validate
     * @param _proposalType Type of proposal
     * @param _proposalData Encoded proposal data
     */
    function createConsensusProposal(
        bytes32 _dataHash,
        string memory _proposalType,
        bytes memory _proposalData
    ) public onlyActiveValidator returns (uint256) {
        require(!processedValidations[_dataHash], "Already processed");
        
        uint256 proposalId = ++proposalCounter;
        
        ConsensusProposal storage proposal = proposals[proposalId];
        proposal.proposalId = proposalId;
        proposal.proposer = msg.sender;
        proposal.dataHash = _dataHash;
        proposal.proposalType = _proposalType;
        proposal.proposalData = _proposalData;
        proposal.status = ProposalStatus.PENDING;
        proposal.createdAt = block.timestamp;
        proposal.expiresAt = block.timestamp + PROPOSAL_DURATION;
        
        emit ProposalCreated(proposalId, msg.sender, _proposalType);
        
        return proposalId;
    }
    
    /**
     * @dev Vote on a consensus proposal
     * @param _proposalId ID of the proposal
     * @param _support Whether to support the proposal
     */
    function voteOnProposal(uint256 _proposalId, bool _support) external onlyActiveValidator {
        ConsensusProposal storage proposal = proposals[_proposalId];
        require(proposal.status == ProposalStatus.PENDING, "Proposal not pending");
        require(block.timestamp <= proposal.expiresAt, "Proposal expired");
        require(!proposal.hasVoted[msg.sender], "Already voted");
        
        proposal.hasVoted[msg.sender] = true;
        proposal.voteValue[msg.sender] = _support;
        proposal.totalVotes++;
        
        // Weight vote by stake
        uint256 voteWeight = validators[msg.sender].stakedAmount;
        
        if (_support) {
            proposal.votesFor += voteWeight;
        } else {
            proposal.votesAgainst += voteWeight;
        }
        
        emit VoteCast(_proposalId, msg.sender, _support);
        
        // Check if we have enough votes to execute
        _checkAndExecuteProposal(_proposalId);
    }
    
    /**
     * @dev Check if proposal has reached consensus and execute
     * @param _proposalId ID of the proposal
     */
    function _checkAndExecuteProposal(uint256 _proposalId) internal {
        ConsensusProposal storage proposal = proposals[_proposalId];
        
        // Need participation from at least 2/3 of validators
        uint256 requiredParticipation = (activeValidatorList.length * 2) / 3;
        if (proposal.totalVotes < requiredParticipation && proposal.totalVotes < MINIMUM_VALIDATORS) {
            return;
        }
        
        uint256 totalVoteWeight = proposal.votesFor + proposal.votesAgainst;
        if (totalVoteWeight == 0) return;
        
        uint256 approvalPercentage = (proposal.votesFor * 100) / totalVoteWeight;
        
        if (approvalPercentage >= BYZANTINE_THRESHOLD) {
            proposal.status = ProposalStatus.APPROVED;
            proposal.executedAt = block.timestamp;
            processedValidations[proposal.dataHash] = true;
            
            // Reward validators who voted correctly
            _distributeRewards(_proposalId, true);
            
            // Execute proposal action
            _executeProposalAction(proposal);
            
            emit ProposalExecuted(_proposalId, true);
        } else if (approvalPercentage < (100 - BYZANTINE_THRESHOLD)) {
            proposal.status = ProposalStatus.REJECTED;
            proposal.executedAt = block.timestamp;
            
            // Punish validators who voted incorrectly
            _distributeRewards(_proposalId, false);
            
            emit ProposalExecuted(_proposalId, false);
        }
    }
    
    /**
     * @dev Execute the action specified in an approved proposal
     * @param proposal The approved proposal
     */
    function _executeProposalAction(ConsensusProposal storage proposal) internal {
        // Decode and execute based on proposal type
        if (keccak256(bytes(proposal.proposalType)) == keccak256("TRUST_UPDATE")) {
            // Call TrustOracle to update trust score
            (bool success,) = trustOracleAddress.call(proposal.proposalData);
            require(success, "Trust update failed");
        } else if (keccak256(bytes(proposal.proposalType)) == keccak256("PROOF_VALIDATION")) {
            // Call ProofRegistry to validate proof
            (bool success,) = proofRegistryAddress.call(proposal.proposalData);
            require(success, "Proof validation failed");
        }
        
        emit ValidationRecorded(proposal.dataHash, proposal.proposer, true);
    }
    
    /**
     * @dev Distribute rewards to validators based on voting outcome
     * @param _proposalId ID of the proposal
     * @param _approvedOutcome Whether the proposal was approved
     */
    function _distributeRewards(uint256 _proposalId, bool _approvedOutcome) internal {
        ConsensusProposal storage proposal = proposals[_proposalId];
        uint256 rewardPerValidator = rewardPool / (proposal.totalVotes > 0 ? proposal.totalVotes : 1);
        
        for (uint256 i = 0; i < activeValidatorList.length; i++) {
            address validator = activeValidatorList[i];
            if (proposal.hasVoted[validator]) {
                bool votedCorrectly = proposal.voteValue[validator] == _approvedOutcome;
                
                if (votedCorrectly) {
                    // Reward for correct vote
                    pendingRewards[validator] += rewardPerValidator;
                    validators[validator].successfulValidations++;
                    validators[validator].reputationScore = min(100, validators[validator].reputationScore + 1);
                    
                    emit RewardDistributed(validator, rewardPerValidator);
                } else {
                    // Penalty for incorrect vote
                    validators[validator].failedValidations++;
                    validators[validator].reputationScore = validators[validator].reputationScore > 5 ? 
                        validators[validator].reputationScore - 5 : 0;
                    
                    // Slash if reputation too low
                    if (validators[validator].reputationScore < 20) {
                        _slashValidator(validator, "Low reputation");
                    }
                }
                
                validators[validator].totalValidations++;
            }
        }
    }
    
    /**
     * @dev Record validation from an AI agent
     * @param _agentId ID of the AI agent
     * @param _validationHash Hash of the validation
     * @param _confidence Confidence level (0-100)
     * @param _validationType Type of validation
     */
    function recordAIValidation(
        string memory _agentId,
        bytes32 _validationHash,
        uint256 _confidence,
        string memory _validationType
    ) external onlyActiveValidator {
        require(validators[msg.sender].isAIAgent, "Not an AI validator");
        require(_confidence <= 100, "Invalid confidence");
        
        AIValidation memory validation = AIValidation({
            agentId: _agentId,
            agentWallet: msg.sender,
            validationHash: _validationHash,
            confidence: _confidence,
            validationType: _validationType,
            timestamp: block.timestamp,
            isValid: true
        });
        
        aiValidations[_agentId].push(validation);
        
        // Update validator activity
        validators[msg.sender].lastActiveBlock = block.number;
        validators[msg.sender].totalValidations++;
        
        emit AIValidationRecorded(_agentId, _validationHash, _confidence);
        
        // If confidence is high enough, auto-create proposal
        if (_confidence >= 80) {
            bytes memory proposalData = abi.encode(msg.sender, _validationHash, _confidence);
            createConsensusProposal(_validationHash, _validationType, proposalData);
        }
    }
    
    /**
     * @dev Slash a validator for misbehavior
     * @param _validator Address of the validator to slash
     * @param _reason Reason for slashing
     */
    function _slashValidator(address _validator, string memory _reason) internal {
        Validator storage validator = validators[_validator];
        
        uint256 penalty = (validator.stakedAmount * SLASHING_PENALTY) / 100;
        validator.stakedAmount -= penalty;
        validator.slashingEvents++;
        rewardPool += penalty;
        
        if (validator.slashingEvents >= 3 || validator.stakedAmount < MINIMUM_STAKE) {
            validator.status = ValidatorStatus.SLASHED;
            _removeFromActiveList(_validator);
        } else {
            validator.status = ValidatorStatus.SUSPENDED;
        }
        
        emit ValidatorSlashed(_validator, penalty, _reason);
    }
    
    /**
     * @dev Exit as a validator and withdraw stake
     */
    function exitAsValidator() external validatorExists(msg.sender) {
        Validator storage validator = validators[msg.sender];
        require(validator.status != ValidatorStatus.SLASHED, "Validator is slashed");
        
        uint256 stakeToReturn = validator.stakedAmount;
        uint256 rewards = pendingRewards[msg.sender];
        uint256 totalReturn = stakeToReturn + rewards;
        
        validator.status = ValidatorStatus.INACTIVE;
        validator.stakedAmount = 0;
        pendingRewards[msg.sender] = 0;
        totalStaked -= stakeToReturn;
        
        _removeFromActiveList(msg.sender);
        
        (bool success,) = msg.sender.call{value: totalReturn}("");
        require(success, "Transfer failed");
        
        emit ValidatorExited(msg.sender, totalReturn);
    }
    
    /**
     * @dev Claim pending rewards
     */
    function claimRewards() external {
        uint256 rewards = pendingRewards[msg.sender];
        require(rewards > 0, "No rewards");
        
        pendingRewards[msg.sender] = 0;
        
        (bool success,) = msg.sender.call{value: rewards}("");
        require(success, "Transfer failed");
        
        emit RewardDistributed(msg.sender, rewards);
    }
    
    /**
     * @dev Check validator health and slash inactive ones
     */
    function checkValidatorHealth() external {
        for (uint256 i = 0; i < activeValidatorList.length; i++) {
            address validator = activeValidatorList[i];
            Validator storage v = validators[validator];
            
            if (block.number - v.lastActiveBlock > VALIDATOR_TIMEOUT) {
                _slashValidator(validator, "Inactivity");
            }
        }
    }
    
    /**
     * @dev Remove validator from active list
     * @param _validator Address to remove
     */
    function _removeFromActiveList(address _validator) internal {
        for (uint256 i = 0; i < activeValidatorList.length; i++) {
            if (activeValidatorList[i] == _validator) {
                activeValidatorList[i] = activeValidatorList[activeValidatorList.length - 1];
                activeValidatorList.pop();
                break;
            }
        }
    }
    
    /**
     * @dev Get active validator count
     */
    function getActiveValidatorCount() external view returns (uint256) {
        return activeValidatorList.length;
    }
    
    /**
     * @dev Get all active validators
     */
    function getActiveValidators() external view returns (address[] memory) {
        return activeValidatorList;
    }
    
    /**
     * @dev Check if consensus is possible
     */
    function isConsensusReady() external view returns (bool) {
        return activeValidatorList.length >= MINIMUM_VALIDATORS;
    }
    
    /**
     * @dev Get validator details
     */
    function getValidatorDetails(address _validator) external view returns (Validator memory) {
        return validators[_validator];
    }
    
    /**
     * @dev Fund reward pool
     */
    function fundRewardPool() external payable {
        rewardPool += msg.value;
    }
    
    /**
     * @dev Update contract addresses
     */
    function updateContractAddresses(address _trustOracle, address _proofRegistry) external onlyAdmin {
        trustOracleAddress = _trustOracle;
        proofRegistryAddress = _proofRegistry;
    }
    
    /**
     * @dev Min function
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
    
    /**
     * @dev Batch validator operations for gas optimization
     * @param _validators Array of validator addresses
     * @param _actions Array of actions (0=suspend, 1=reactivate, 2=slash)
     */
    function batchValidatorOperations(
        address[] memory _validators,
        uint256[] memory _actions
    ) external onlyAdmin {
        require(_validators.length == _actions.length, "Array mismatch");
        
        for (uint256 i = 0; i < _validators.length; i++) {
            Validator storage v = validators[_validators[i]];
            if (v.validatorAddress == address(0)) continue;
            
            if (_actions[i] == 0) {
                v.status = ValidatorStatus.SUSPENDED;
            } else if (_actions[i] == 1 && v.status == ValidatorStatus.SUSPENDED) {
                v.status = ValidatorStatus.ACTIVE;
            } else if (_actions[i] == 2) {
                _slashValidator(_validators[i], "Admin action");
            }
        }
    }
    
    /**
     * @dev Emergency pause for critical situations
     */
    bool public emergencyPause;
    
    modifier notPaused() {
        require(!emergencyPause, "Contract paused");
        _;
    }
    
    function toggleEmergencyPause() external onlyAdmin {
        emergencyPause = !emergencyPause;
    }
    
    /**
     * @dev Get proposal status
     */
    function getProposalStatus(uint256 _proposalId) external view returns (ProposalStatus) {
        return proposals[_proposalId].status;
    }
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "viaIR": true,
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
Governance, Staking, Voting, Factory|addr:0x18e6f0b84f10406c879fc8f9d898698b3afe6c67|verified:true|block:23461346|tx:0x9bb2d71b77839cfdfac8bc10f29092407ab73527fb48a9be2f2cfa7bd7132ea7|first_check:1759064549

Submitted on: 2025-09-28 15:02:30

Comments

Log in to comment.

No comments yet.