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"
]
}
}
}
}}
Submitted on: 2025-09-28 15:02:30
Comments
Log in to comment.
No comments yet.