mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Update XDCValidator.sol
This commit is contained in:
parent
1720858916
commit
dae2413c4c
1 changed files with 163 additions and 71 deletions
|
|
@ -1,9 +1,7 @@
|
||||||
|
|
||||||
pragma solidity ^0.4.21;
|
pragma solidity ^0.4.21;
|
||||||
|
|
||||||
import "./libs/SafeMath.sol";
|
import "./libs/SafeMath.sol";
|
||||||
|
|
||||||
|
|
||||||
contract XDCValidator {
|
contract XDCValidator {
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
|
|
@ -49,20 +47,22 @@ contract XDCValidator {
|
||||||
uint256 public candidateWithdrawDelay;
|
uint256 public candidateWithdrawDelay;
|
||||||
uint256 public voterWithdrawDelay;
|
uint256 public voterWithdrawDelay;
|
||||||
|
|
||||||
modifier onlyValidCandidateCap {
|
modifier onlyValidCandidateCap() {
|
||||||
// anyone can deposit X XDC to become a candidate
|
// anyone can deposit X XDC to become a candidate
|
||||||
require(msg.value >= minCandidateCap);
|
require(msg.value >= minCandidateCap);
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier onlyValidVoterCap {
|
modifier onlyValidVoterCap() {
|
||||||
|
|
||||||
require(msg.value >= minVoterCap);
|
require(msg.value >= minVoterCap);
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier onlyKYCWhitelisted {
|
modifier onlyKYCWhitelisted() {
|
||||||
require(KYCString[msg.sender].length!=0 || ownerToCandidate[msg.sender].length>0);
|
require(
|
||||||
|
KYCString[msg.sender].length != 0 ||
|
||||||
|
ownerToCandidate[msg.sender].length > 0
|
||||||
|
);
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +89,10 @@ contract XDCValidator {
|
||||||
modifier onlyValidVote(address _candidate, uint256 _cap) {
|
modifier onlyValidVote(address _candidate, uint256 _cap) {
|
||||||
require(validatorsState[_candidate].voters[msg.sender] >= _cap);
|
require(validatorsState[_candidate].voters[msg.sender] >= _cap);
|
||||||
if (validatorsState[_candidate].owner == msg.sender) {
|
if (validatorsState[_candidate].owner == msg.sender) {
|
||||||
require(validatorsState[_candidate].voters[msg.sender].sub(_cap) >= minCandidateCap);
|
require(
|
||||||
|
validatorsState[_candidate].voters[msg.sender].sub(_cap) >=
|
||||||
|
minCandidateCap
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +101,9 @@ contract XDCValidator {
|
||||||
require(_blockNumber > 0);
|
require(_blockNumber > 0);
|
||||||
require(block.number >= _blockNumber);
|
require(block.number >= _blockNumber);
|
||||||
require(withdrawsState[msg.sender].caps[_blockNumber] > 0);
|
require(withdrawsState[msg.sender].caps[_blockNumber] > 0);
|
||||||
require(withdrawsState[msg.sender].blockNumbers[_index] == _blockNumber);
|
require(
|
||||||
|
withdrawsState[msg.sender].blockNumbers[_index] == _blockNumber
|
||||||
|
);
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,11 +134,12 @@ contract XDCValidator {
|
||||||
});
|
});
|
||||||
voters[_candidates[i]].push(_firstOwner);
|
voters[_candidates[i]].push(_firstOwner);
|
||||||
ownerToCandidate[_firstOwner].push(_candidates[i]);
|
ownerToCandidate[_firstOwner].push(_candidates[i]);
|
||||||
validatorsState[_candidates[i]].voters[_firstOwner] = minCandidateCap;
|
validatorsState[_candidates[i]].voters[
|
||||||
|
_firstOwner
|
||||||
|
] = minCandidateCap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// uploadKYC : anyone can upload a KYC; its not equivalent to becoming an owner.
|
// uploadKYC : anyone can upload a KYC; its not equivalent to becoming an owner.
|
||||||
function uploadKYC(string kychash) external {
|
function uploadKYC(string kychash) external {
|
||||||
KYCString[msg.sender].push(kychash);
|
KYCString[msg.sender].push(kychash);
|
||||||
|
|
@ -141,7 +147,15 @@ contract XDCValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// propose : any non-candidate who has uploaded its KYC can become an owner by proposing a candidate.
|
// propose : any non-candidate who has uploaded its KYC can become an owner by proposing a candidate.
|
||||||
function propose(address _candidate) external payable onlyValidCandidateCap onlyKYCWhitelisted onlyNotCandidate(_candidate) {
|
function propose(
|
||||||
|
address _candidate
|
||||||
|
)
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
onlyValidCandidateCap
|
||||||
|
onlyKYCWhitelisted
|
||||||
|
onlyNotCandidate(_candidate)
|
||||||
|
{
|
||||||
uint256 cap = validatorsState[_candidate].cap.add(msg.value);
|
uint256 cap = validatorsState[_candidate].cap.add(msg.value);
|
||||||
candidates.push(_candidate);
|
candidates.push(_candidate);
|
||||||
validatorsState[_candidate] = ValidatorState({
|
validatorsState[_candidate] = ValidatorState({
|
||||||
|
|
@ -149,7 +163,9 @@ contract XDCValidator {
|
||||||
isCandidate: true,
|
isCandidate: true,
|
||||||
cap: cap
|
cap: cap
|
||||||
});
|
});
|
||||||
validatorsState[_candidate].voters[msg.sender] = validatorsState[_candidate].voters[msg.sender].add(msg.value);
|
validatorsState[_candidate].voters[msg.sender] = validatorsState[
|
||||||
|
_candidate
|
||||||
|
].voters[msg.sender].add(msg.value);
|
||||||
candidateCount = candidateCount.add(1);
|
candidateCount = candidateCount.add(1);
|
||||||
if (ownerToCandidate[msg.sender].length == 0) {
|
if (ownerToCandidate[msg.sender].length == 0) {
|
||||||
owners.push(msg.sender);
|
owners.push(msg.sender);
|
||||||
|
|
@ -160,12 +176,18 @@ contract XDCValidator {
|
||||||
emit Propose(msg.sender, _candidate, msg.value);
|
emit Propose(msg.sender, _candidate, msg.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function vote(address _candidate) external payable onlyValidVoterCap onlyValidCandidate(_candidate) {
|
function vote(
|
||||||
validatorsState[_candidate].cap = validatorsState[_candidate].cap.add(msg.value);
|
address _candidate
|
||||||
|
) external payable onlyValidVoterCap onlyValidCandidate(_candidate) {
|
||||||
|
validatorsState[_candidate].cap = validatorsState[_candidate].cap.add(
|
||||||
|
msg.value
|
||||||
|
);
|
||||||
if (validatorsState[_candidate].voters[msg.sender] == 0) {
|
if (validatorsState[_candidate].voters[msg.sender] == 0) {
|
||||||
voters[_candidate].push(msg.sender);
|
voters[_candidate].push(msg.sender);
|
||||||
}
|
}
|
||||||
validatorsState[_candidate].voters[msg.sender] = validatorsState[_candidate].voters[msg.sender].add(msg.value);
|
validatorsState[_candidate].voters[msg.sender] = validatorsState[
|
||||||
|
_candidate
|
||||||
|
].voters[msg.sender].add(msg.value);
|
||||||
emit Vote(msg.sender, _candidate, msg.value);
|
emit Vote(msg.sender, _candidate, msg.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,11 +199,16 @@ contract XDCValidator {
|
||||||
return validatorsState[_candidate].cap;
|
return validatorsState[_candidate].cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCandidateOwner(address _candidate) public view returns(address) {
|
function getCandidateOwner(
|
||||||
|
address _candidate
|
||||||
|
) public view returns (address) {
|
||||||
return validatorsState[_candidate].owner;
|
return validatorsState[_candidate].owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVoterCap(address _candidate, address _voter) public view returns(uint256) {
|
function getVoterCap(
|
||||||
|
address _candidate,
|
||||||
|
address _voter
|
||||||
|
) public view returns (uint256) {
|
||||||
return validatorsState[_candidate].voters[_voter];
|
return validatorsState[_candidate].voters[_voter];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,65 +224,105 @@ contract XDCValidator {
|
||||||
return withdrawsState[msg.sender].blockNumbers;
|
return withdrawsState[msg.sender].blockNumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWithdrawCap(uint256 _blockNumber) public view returns(uint256) {
|
function getWithdrawCap(
|
||||||
|
uint256 _blockNumber
|
||||||
|
) public view returns (uint256) {
|
||||||
return withdrawsState[msg.sender].caps[_blockNumber];
|
return withdrawsState[msg.sender].caps[_blockNumber];
|
||||||
}
|
}
|
||||||
|
|
||||||
function unvote(address _candidate, uint256 _cap) public onlyValidVote(_candidate, _cap) {
|
function unvote(
|
||||||
validatorsState[_candidate].cap = validatorsState[_candidate].cap.sub(_cap);
|
address _candidate,
|
||||||
validatorsState[_candidate].voters[msg.sender] = validatorsState[_candidate].voters[msg.sender].sub(_cap);
|
uint256 _cap
|
||||||
|
) public onlyValidVote(_candidate, _cap) {
|
||||||
|
validatorsState[_candidate].cap = validatorsState[_candidate].cap.sub(
|
||||||
|
_cap
|
||||||
|
);
|
||||||
|
validatorsState[_candidate].voters[msg.sender] = validatorsState[
|
||||||
|
_candidate
|
||||||
|
].voters[msg.sender].sub(_cap);
|
||||||
|
|
||||||
// refund after delay X blocks
|
// refund after delay X blocks
|
||||||
uint256 withdrawBlockNumber = voterWithdrawDelay.add(block.number);
|
uint256 withdrawBlockNumber = voterWithdrawDelay.add(block.number);
|
||||||
withdrawsState[msg.sender].caps[withdrawBlockNumber] = withdrawsState[msg.sender].caps[withdrawBlockNumber].add(_cap);
|
withdrawsState[msg.sender].caps[withdrawBlockNumber] = withdrawsState[
|
||||||
|
msg.sender
|
||||||
|
].caps[withdrawBlockNumber].add(_cap);
|
||||||
withdrawsState[msg.sender].blockNumbers.push(withdrawBlockNumber);
|
withdrawsState[msg.sender].blockNumbers.push(withdrawBlockNumber);
|
||||||
|
|
||||||
emit Unvote(msg.sender, _candidate, _cap);
|
emit Unvote(msg.sender, _candidate, _cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resign(address _candidate) public onlyOwner(_candidate) onlyCandidate(_candidate) {
|
function resign(
|
||||||
|
address _candidate
|
||||||
|
) public onlyOwner(_candidate) onlyCandidate(_candidate) {
|
||||||
validatorsState[_candidate].isCandidate = false;
|
validatorsState[_candidate].isCandidate = false;
|
||||||
candidateCount = candidateCount.sub(1);
|
candidateCount = candidateCount.sub(1);
|
||||||
for (uint256 i = 0; i < candidates.length; i++) {
|
for (uint256 i = 0; i < candidates.length; i++) {
|
||||||
if (candidates[i] == _candidate) {
|
if (candidates[i] == _candidate) {
|
||||||
|
address[] memory cacheArray = ownerToCandidate[msg.sender];
|
||||||
|
uint256 cacheArrayLength = cacheArray.length;
|
||||||
|
for (uint256 j = 0; j < cacheArrayLength; j++) {
|
||||||
|
if (cacheArray[j] == _candidate) {
|
||||||
|
delete cacheArray[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ownerToCandidate[msg.sender] = removeZeroAddresses(cacheArray);
|
||||||
|
if (ownerToCandidate[msg.sender].length == 0) {
|
||||||
|
ownerCount--;
|
||||||
|
}
|
||||||
delete candidates[i];
|
delete candidates[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
candidates = removeZeroAddresses(candidates);
|
||||||
uint256 cap = validatorsState[_candidate].voters[msg.sender];
|
uint256 cap = validatorsState[_candidate].voters[msg.sender];
|
||||||
validatorsState[_candidate].cap = validatorsState[_candidate].cap.sub(cap);
|
validatorsState[_candidate].cap = validatorsState[_candidate].cap.sub(
|
||||||
|
cap
|
||||||
|
);
|
||||||
validatorsState[_candidate].voters[msg.sender] = 0;
|
validatorsState[_candidate].voters[msg.sender] = 0;
|
||||||
// refunding after resigning X blocks
|
// refunding after resigning X blocks
|
||||||
uint256 withdrawBlockNumber = candidateWithdrawDelay.add(block.number);
|
uint256 withdrawBlockNumber = candidateWithdrawDelay.add(block.number);
|
||||||
withdrawsState[msg.sender].caps[withdrawBlockNumber] = withdrawsState[msg.sender].caps[withdrawBlockNumber].add(cap);
|
withdrawsState[msg.sender].caps[withdrawBlockNumber] = withdrawsState[
|
||||||
|
msg.sender
|
||||||
|
].caps[withdrawBlockNumber].add(cap);
|
||||||
withdrawsState[msg.sender].blockNumbers.push(withdrawBlockNumber);
|
withdrawsState[msg.sender].blockNumbers.push(withdrawBlockNumber);
|
||||||
emit Resign(msg.sender, _candidate);
|
emit Resign(msg.sender, _candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// voteInvalidKYC : any candidate can vote for invalid KYC i.e. a particular candidate's owner has uploaded a bad KYC.
|
// voteInvalidKYC : any candidate can vote for invalid KYC i.e. a particular candidate's owner has uploaded a bad KYC.
|
||||||
// On securing 75% votes against an owner ( not candidate ), owner & all its candidates will lose their funds.
|
// On securing 75% votes against an owner ( not candidate ), owner & all its candidates will lose their funds.
|
||||||
function voteInvalidKYC(address _invalidCandidate) onlyValidCandidate(msg.sender) onlyValidCandidate(_invalidCandidate) public {
|
function voteInvalidKYC(
|
||||||
|
address _invalidCandidate
|
||||||
|
)
|
||||||
|
public
|
||||||
|
onlyValidCandidate(msg.sender)
|
||||||
|
onlyValidCandidate(_invalidCandidate)
|
||||||
|
{
|
||||||
address candidateOwner = getCandidateOwner(msg.sender);
|
address candidateOwner = getCandidateOwner(msg.sender);
|
||||||
address _invalidMasternode = getCandidateOwner(_invalidCandidate);
|
address _invalidMasternode = getCandidateOwner(_invalidCandidate);
|
||||||
require(!hasVotedInvalid[candidateOwner][_invalidMasternode]);
|
require(!hasVotedInvalid[candidateOwner][_invalidMasternode]);
|
||||||
hasVotedInvalid[candidateOwner][_invalidMasternode] = true;
|
hasVotedInvalid[candidateOwner][_invalidMasternode] = true;
|
||||||
invalidKYCCount[_invalidMasternode] += 1;
|
invalidKYCCount[_invalidMasternode] += 1;
|
||||||
if( invalidKYCCount[_invalidMasternode]*100/getOwnerCount() >= 75 ){
|
if (
|
||||||
|
(invalidKYCCount[_invalidMasternode] * 100) / getOwnerCount() >= 75
|
||||||
|
) {
|
||||||
// 75% owners say that the KYC is invalid
|
// 75% owners say that the KYC is invalid
|
||||||
address[] memory allMasternodes = new address[](candidates.length-1) ;
|
address[] memory allMasternodes = new address[](
|
||||||
|
candidates.length - 1
|
||||||
|
);
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
for (uint i = 0; i < candidates.length; i++) {
|
for (uint i = 0; i < candidates.length; i++) {
|
||||||
if (getCandidateOwner(candidates[i]) == _invalidMasternode) {
|
if (getCandidateOwner(candidates[i]) == _invalidMasternode) {
|
||||||
// logic to remove cap.
|
// logic to remove cap.
|
||||||
candidateCount = candidateCount.sub(1);
|
candidateCount = candidateCount.sub(1);
|
||||||
allMasternodes[count++] = candidates[i];
|
allMasternodes[count++] = candidates[i];
|
||||||
delete candidates[i];
|
|
||||||
delete validatorsState[candidates[i]];
|
delete validatorsState[candidates[i]];
|
||||||
|
delete candidates[i];
|
||||||
delete KYCString[_invalidMasternode];
|
delete KYCString[_invalidMasternode];
|
||||||
delete ownerToCandidate[_invalidMasternode];
|
delete ownerToCandidate[_invalidMasternode];
|
||||||
delete invalidKYCCount[_invalidMasternode];
|
delete invalidKYCCount[_invalidMasternode];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
candidates = removeZeroAddresses(candidates);
|
||||||
for (uint k = 0; k < owners.length; k++) {
|
for (uint k = 0; k < owners.length; k++) {
|
||||||
if (owners[k] == _invalidMasternode) {
|
if (owners[k] == _invalidMasternode) {
|
||||||
delete owners[k];
|
delete owners[k];
|
||||||
|
|
@ -263,41 +330,66 @@ contract XDCValidator {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
owners = removeZeroAddresses(owners);
|
||||||
emit InvalidatedNode(_invalidMasternode, allMasternodes);
|
emit InvalidatedNode(_invalidMasternode, allMasternodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidPercent : get votes against an owner in percentage.
|
// invalidPercent : get votes against an owner in percentage.
|
||||||
function invalidPercent(address _invalidCandidate) onlyValidCandidate(_invalidCandidate) view public returns(uint){
|
function invalidPercent(
|
||||||
|
address _invalidCandidate
|
||||||
|
) public view onlyValidCandidate(_invalidCandidate) returns (uint) {
|
||||||
address _invalidMasternode = getCandidateOwner(_invalidCandidate);
|
address _invalidMasternode = getCandidateOwner(_invalidCandidate);
|
||||||
return (invalidKYCCount[_invalidMasternode]*100/getOwnerCount());
|
return ((invalidKYCCount[_invalidMasternode] * 100) / getOwnerCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// getOwnerCount : get count of total owners; accounts who own atleast one masternode.
|
// getOwnerCount : get count of total owners; accounts who own atleast one masternode.
|
||||||
function getOwnerCount() view public returns (uint){
|
function getOwnerCount() public view returns (uint) {
|
||||||
return ownerCount;
|
return ownerCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// getKYC : get KYC uploaded of the owner of the given masternode or the owner themselves
|
// getKYC : get KYC uploaded of the owner of the given masternode or the owner themselves
|
||||||
function getLatestKYC(address _address) view public returns (string) {
|
function getLatestKYC(address _address) public view returns (string) {
|
||||||
if (isCandidate(_address)) {
|
if (isCandidate(_address)) {
|
||||||
return KYCString[getCandidateOwner(_address)][KYCString[getCandidateOwner(_address)].length-1];
|
return
|
||||||
}
|
KYCString[getCandidateOwner(_address)][
|
||||||
else{
|
KYCString[getCandidateOwner(_address)].length - 1
|
||||||
|
];
|
||||||
|
} else {
|
||||||
return KYCString[_address][KYCString[_address].length - 1];
|
return KYCString[_address][KYCString[_address].length - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHashCount(address _address) view public returns(uint){
|
function getHashCount(address _address) public view returns (uint) {
|
||||||
return KYCString[_address].length;
|
return KYCString[_address].length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function withdraw(uint256 _blockNumber, uint _index) public onlyValidWithdraw(_blockNumber, _index) {
|
function withdraw(
|
||||||
|
uint256 _blockNumber,
|
||||||
|
uint _index
|
||||||
|
) public onlyValidWithdraw(_blockNumber, _index) {
|
||||||
uint256 cap = withdrawsState[msg.sender].caps[_blockNumber];
|
uint256 cap = withdrawsState[msg.sender].caps[_blockNumber];
|
||||||
delete withdrawsState[msg.sender].caps[_blockNumber];
|
delete withdrawsState[msg.sender].caps[_blockNumber];
|
||||||
delete withdrawsState[msg.sender].blockNumbers[_index];
|
delete withdrawsState[msg.sender].blockNumbers[_index];
|
||||||
msg.sender.transfer(cap);
|
msg.sender.transfer(cap);
|
||||||
emit Withdraw(msg.sender, _blockNumber, cap);
|
emit Withdraw(msg.sender, _blockNumber, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeZeroAddresses(
|
||||||
|
address[] memory addresses
|
||||||
|
) private pure returns (address[] memory) {
|
||||||
|
address[] memory newAddresses = new address[](addresses.length);
|
||||||
|
uint256 j = 0;
|
||||||
|
for (uint256 i = 0; i < addresses.length; i++) {
|
||||||
|
if (addresses[i] != address(0)) {
|
||||||
|
newAddresses[j] = addresses[i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Resize the array.
|
||||||
|
assembly {
|
||||||
|
mstore(newAddresses, j)
|
||||||
|
}
|
||||||
|
return newAddresses;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue