github.com/vantum/vantum@v0.0.0-20180815184342-fe37d5f7a990/contracts/masternode/contract/masternode.sol (about) 1 pragma solidity ^0.4.11; 2 3 contract Masternode { 4 5 uint public constant etzPerNode = 20 * 10 ** 18; 6 uint public constant etzMin = 10 ** 16; 7 uint public constant blockPingTimeout = 3600; 8 9 bytes8 public lastId; 10 uint public count; 11 12 struct node { 13 bytes32 id1; 14 bytes32 id2; 15 bytes8 preId; 16 bytes8 nextId; 17 address account; 18 uint block; 19 20 uint blockOnlineAcc; 21 uint blockLastPing; 22 } 23 24 mapping (bytes8 => node) nodes; 25 mapping (address => bytes8) ids; 26 mapping (address => bytes8) nodeAddressToId; 27 28 uint public constant proposalPeriod = 1200000; 29 uint public constant proposalFee = 10 * 10 ** 18; 30 address public governanceAddress; 31 address public lastProposalAddress; 32 struct vote { 33 uint voteCount; 34 uint startBlock; 35 uint stopBlock; 36 address creator; 37 address lastAddress; 38 } 39 40 mapping(address => mapping(address => bool)) voters; 41 mapping (address => vote) votes; 42 43 event join(bytes8 id, address addr); 44 event quit(bytes8 id, address addr); 45 event ping(bytes8 id, uint blockOnlineAcc, uint blockLastPing); 46 47 constructor() public { 48 lastId = bytes8(0); 49 count = 0; 50 } 51 52 function register(bytes32 id1, bytes32 id2) payable public { 53 bytes8 id = bytes8(id1); 54 require( 55 bytes32(0) != id1 && 56 bytes32(0) != id2 && 57 bytes8(0) != id && 58 bytes8(0) == ids[msg.sender] && 59 bytes32(0) == nodes[id].id1 && 60 msg.value == etzPerNode 61 ); 62 bytes32[2] memory input; 63 bytes32[1] memory output; 64 input[0] = id1; 65 input[1] = id2; 66 assembly { 67 if iszero(call(not(0), 0x0b, 0, input, 128, output, 32)) { 68 revert(0, 0) 69 } 70 } 71 address account = address(output[0]); 72 require(account != address(0)); 73 74 ids[msg.sender] = id; 75 nodes[id] = node( 76 id1, 77 id2, 78 lastId, 79 bytes8(0), 80 msg.sender, 81 block.number, 82 uint(0), 83 uint(0) 84 ); 85 if(lastId != bytes8(0)){ 86 nodes[lastId].nextId = id; 87 } 88 lastId = id; 89 count += 1; 90 nodeAddressToId[account] = id; 91 account.transfer(etzMin); 92 emit join(id, msg.sender); 93 } 94 95 function() payable public { 96 require(msg.value == 0); 97 bytes8 id = nodeAddressToId[msg.sender]; 98 if (id != bytes8(0) && has(id)){ 99 // ping 100 uint blockLastPing = nodes[id].blockLastPing; 101 if(blockLastPing > 0){ 102 uint blockGap = block.number - blockLastPing; 103 if(blockGap > blockPingTimeout){ 104 nodes[id].blockOnlineAcc = 0; 105 }else{ 106 nodes[id].blockOnlineAcc += blockGap; 107 } 108 } 109 nodes[id].blockLastPing = block.number; 110 emit ping(id, nodes[id].blockOnlineAcc, block.number); 111 }else{ 112 id = ids[msg.sender]; 113 bytes32 id1 = nodes[id].id1; 114 require( 115 msg.value == 0 && 116 bytes8(0) != id && 117 bytes32(0) != id1 && 118 address(this).balance >= (etzPerNode - etzMin) && 119 count > 0 120 ); 121 122 bytes32[2] memory input; 123 bytes32[1] memory output; 124 input[0] = id1; 125 input[1] = nodes[id].id2; 126 assembly { 127 if iszero(call(not(0), 0x0b, 0, input, 128, output, 32)) { 128 revert(0, 0) 129 } 130 } 131 address account = address(output[0]); 132 nodeAddressToId[account] = bytes8(0); 133 134 bytes8 preId = nodes[id].preId; 135 bytes8 nextId = nodes[id].nextId; 136 if(preId != bytes8(0)){ 137 nodes[preId].nextId = nextId; 138 } 139 if(nextId != bytes8(0)){ 140 nodes[nextId].preId = preId; 141 }else{ 142 lastId = preId; 143 } 144 nodes[id] = node( 145 bytes32(0), 146 bytes32(0), 147 bytes8(0), 148 bytes8(0), 149 address(0), 150 uint(0), 151 uint(0), 152 uint(0) 153 ); 154 ids[msg.sender] = bytes8(0); 155 count -= 1; 156 emit quit(id, msg.sender); 157 msg.sender.transfer(etzPerNode - etzMin); 158 } 159 160 } 161 162 function getInfo(bytes8 id) constant public returns ( 163 bytes32 id1, 164 bytes32 id2, 165 bytes8 preId, 166 bytes8 nextId, 167 uint blockNumber, 168 address account, 169 uint blockOnlineAcc, 170 uint blockLastPing 171 ) 172 { 173 id1 = nodes[id].id1; 174 id2 = nodes[id].id2; 175 preId = nodes[id].preId; 176 nextId = nodes[id].nextId; 177 blockNumber = nodes[id].block; 178 account = nodes[id].account; 179 blockOnlineAcc = nodes[id].blockOnlineAcc; 180 blockLastPing = nodes[id].blockLastPing; 181 } 182 183 function getId(address addr) constant public returns (bytes8 id) 184 { 185 id = ids[addr]; 186 } 187 188 function has(bytes8 id) constant public returns (bool) 189 { 190 return nodes[id].id1 != bytes32(0); 191 } 192 193 function createGovernanceAddressVote(address addr) payable public 194 { 195 require(votes[addr].voteCount == 0 196 && votes[addr].startBlock == 0 197 && msg.value == proposalFee); 198 votes[addr] = vote({ 199 voteCount: 0, 200 startBlock: block.number, 201 stopBlock: block.number + proposalPeriod, 202 creator: msg.sender, 203 lastAddress: lastProposalAddress 204 }); 205 lastProposalAddress = addr; 206 } 207 208 function voteForGovernanceAddress(address addr) public 209 { 210 vote storage v = votes[addr]; 211 bytes8 id = getId(msg.sender); 212 require(v.startBlock > 0 213 && block.number > v.startBlock 214 && block.number < v.stopBlock 215 && id != bytes8(0) 216 && (block.number - nodes[id].block) > proposalPeriod 217 && voters[addr][msg.sender] == false); 218 voters[addr][msg.sender] = true; 219 v.voteCount += 1; 220 if (v.voteCount > (count / 2)) 221 { 222 v.stopBlock = block.number; 223 governanceAddress = addr; 224 } 225 } 226 227 function getVoteInfo(address addr) constant public returns ( 228 uint voteCount, 229 uint startBlock, 230 uint stopBlock, 231 address creator, 232 address lastAddress 233 ) 234 { 235 voteCount = votes[addr].voteCount; 236 startBlock = votes[addr].startBlock; 237 stopBlock = votes[addr].stopBlock; 238 creator = votes[addr].creator; 239 lastAddress = votes[addr].lastAddress; 240 } 241 }