github.com/codingfuture/orig-energi3@v0.8.4/energi/contracts/src/MasternodeRegistryV1.sol (about) 1 // Copyright 2019 The Energi Core Authors 2 // This file is part of Energi Core. 3 // 4 // Energi Core is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Energi Core is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Energi Core. If not, see <http://www.gnu.org/licenses/>. 16 17 // Energi Governance system is the fundamental part of Energi Core. 18 19 // NOTE: It's not allowed to change the compiler due to byte-to-byte 20 // match requirement. 21 pragma solidity 0.5.16; 22 //pragma experimental SMTChecker; 23 24 import { GlobalConstants } from "./constants.sol"; 25 import { IGovernedContract, GovernedContract } from "./GovernedContract.sol"; 26 import { IGovernedProxy } from "./IGovernedProxy.sol"; 27 import { IBlockReward } from "./IBlockReward.sol"; 28 import { IMasternodeRegistry } from "./IMasternodeRegistry.sol"; 29 import { IMasternodeToken } from "./IMasternodeToken.sol"; 30 import { ITreasury } from "./ITreasury.sol"; 31 import { NonReentrant } from "./NonReentrant.sol"; 32 import { StorageBase } from "./StorageBase.sol"; 33 34 35 /** 36 * Permanent storage of Masternode Registry V1 data. 37 */ 38 contract StorageMasternodeRegistryV1 is 39 StorageBase 40 { 41 struct Info { 42 uint announced_block; 43 uint collateral; 44 bytes32 enode_0; 45 bytes32 enode_1; 46 address payable owner; 47 address prev; 48 address next; 49 uint32 ipv4address; 50 } 51 52 mapping(address => Info) public masternodes; 53 mapping(address => address) public owner_masternodes; 54 55 // NOTE: ABIEncoderV2 is not acceptable at the moment of development! 56 57 /** 58 * For initial setup. 59 */ 60 function setMasternode( 61 address _masternode, 62 address payable _owner, 63 uint32 _ipv4address, 64 bytes32[2] calldata _enode, 65 uint _collateral, 66 uint _announced_block, 67 address _prev, 68 address _next 69 ) 70 external 71 requireOwner 72 { 73 Info storage item = masternodes[_masternode]; 74 address old_owner = item.owner; 75 76 if (old_owner != _owner) { 77 assert(old_owner == address(0)); 78 owner_masternodes[_owner] = _masternode; 79 } 80 81 item.owner = _owner; 82 item.ipv4address = _ipv4address; 83 item.enode_0 = _enode[0]; 84 item.enode_1 = _enode[1]; 85 item.collateral = _collateral; 86 item.announced_block = _announced_block; 87 item.prev = _prev; 88 item.next = _next; 89 } 90 91 /** 92 * NOTE: Extra booleans are just more failsafe than bitfield or other approaches. 93 * Conditional assignment is required to save gas. 94 */ 95 function setMasternodePos( 96 address _masternode, 97 bool _set_prev, address _prev, 98 bool _set_next, address _next 99 ) 100 external 101 requireOwner 102 { 103 Info storage item = masternodes[_masternode]; 104 105 if (_set_prev) item.prev = _prev; 106 if (_set_next) item.next = _next; 107 } 108 109 function deleteMasternode(address _masternode) 110 external 111 requireOwner 112 { 113 delete owner_masternodes[masternodes[_masternode].owner]; 114 delete masternodes[_masternode]; 115 } 116 } 117 118 119 /** 120 * MN-2: Genesis hardcoded version of MasternodeRegistry 121 * 122 * NOTE: it MUST NOT change after blockchain launch! 123 */ 124 contract MasternodeRegistryV1 is 125 GlobalConstants, 126 GovernedContract, 127 IBlockReward, 128 IMasternodeRegistry, 129 NonReentrant 130 { 131 // NOTE: maybe this is too much... 132 event Heartbeat( 133 address indexed masternode 134 ); 135 136 enum Config { 137 RequireValidation, 138 ValidationPeriod, 139 CleanupPeriod, 140 InitialEverCollateral 141 } 142 143 // Data for migration 144 //--------------------------------- 145 StorageMasternodeRegistryV1 public v1storage; 146 147 IGovernedProxy public token_proxy; 148 IGovernedProxy public treasury_proxy; 149 150 uint public mn_announced; 151 152 address public current_masternode; 153 uint public current_payouts; 154 uint public require_validation; 155 uint public validation_period; 156 uint public cleanup_period; 157 //--------------------------------- 158 159 // Not for migration 160 struct Status { 161 uint256 sw_features; 162 uint last_heartbeat; 163 uint inactive_since; 164 uint validator_index; 165 uint invalidation_since; 166 uint invalidations; 167 uint seq_payouts; 168 uint last_vote_epoch; 169 } 170 171 uint public mn_ever_collateral; 172 uint public mn_active_collateral; 173 uint public mn_announced_collateral; 174 175 uint public mn_active; 176 mapping(address => Status) public mn_status; 177 address[] public validator_list; 178 uint last_block_number; 179 //--------------------------------- 180 181 constructor( 182 address _proxy, 183 IGovernedProxy _token_proxy, 184 IGovernedProxy _treasury_proxy, 185 uint[4] memory _config 186 ) 187 public 188 GovernedContract(_proxy) 189 { 190 v1storage = new StorageMasternodeRegistryV1(); 191 token_proxy = _token_proxy; 192 treasury_proxy = _treasury_proxy; 193 194 require_validation = _config[uint(Config.RequireValidation)]; 195 validation_period = _config[uint(Config.ValidationPeriod)]; 196 cleanup_period = _config[uint(Config.CleanupPeriod)]; 197 198 uint initial_ever_collateral = _config[uint(Config.InitialEverCollateral)]; 199 mn_ever_collateral = initial_ever_collateral; 200 require(initial_ever_collateral >= MN_COLLATERAL_MIN, "Initial collateral"); 201 } 202 203 // IMasternodeRegistry 204 //--------------------------------- 205 206 enum ValidationStatus { 207 MNActive, 208 MNCollaterIssue, 209 MNNotActive, 210 MNHeartbeat 211 } 212 213 uint constant internal GAS_RESERVE = 100000; 214 215 // solium-disable security/no-block-members 216 217 // Announcement 218 //================================= 219 220 function announce(address masternode, uint32 ipv4address, bytes32[2] calldata enode) 221 external 222 noReentry 223 { 224 address owner = _callerAddress(); 225 StorageMasternodeRegistryV1 mn_storage = v1storage; 226 227 // Check collateral 228 //--- 229 uint balance = _announce_checkbalance(owner); 230 231 // Cleanup & checks 232 //--- 233 _announce_clear_old(mn_storage, owner); 234 _announce_check_free(mn_storage, masternode); 235 _announce_check_ipv4(ipv4address); 236 237 // Insert into list 238 //--- 239 (address next, address prev) = _announce_insert(mn_storage, masternode); 240 241 // Save 242 //--- 243 mn_storage.setMasternode( 244 masternode, 245 address(uint160(owner)), 246 ipv4address, 247 enode, 248 balance, 249 block.number, 250 prev, 251 next 252 ); 253 254 Status storage mnstatus = mn_status[masternode]; 255 mnstatus.last_heartbeat = block.timestamp; 256 mnstatus.seq_payouts = balance / MN_COLLATERAL_MIN; 257 ++mn_active; 258 ++mn_announced; 259 260 mn_active_collateral += balance; 261 uint announced_collateral = mn_announced_collateral; 262 announced_collateral += balance; 263 mn_announced_collateral = announced_collateral; 264 265 if (announced_collateral > mn_ever_collateral) { 266 mn_ever_collateral = announced_collateral; 267 } 268 269 // Validator logic is de-coupled for easier changes 270 //--- 271 mnstatus.invalidation_since = block.number; 272 mnstatus.validator_index = validator_list.length; 273 validator_list.push(masternode); 274 275 // Event 276 //--- 277 emit Announced(masternode, owner, ipv4address, enode, balance); 278 } 279 280 function _announce_checkbalance(address owner) internal view returns(uint balance) { 281 (balance,) = IMasternodeToken(address(token_proxy.impl())).balanceInfo(owner); 282 require(balance >= MN_COLLATERAL_MIN, "Invalid collateral"); 283 284 } 285 286 function _announce_clear_old(StorageMasternodeRegistryV1 mn_storage, address owner) internal { 287 address old_masternode = mn_storage.owner_masternodes(owner); 288 289 // Regardless if it is re-announcement 290 if (old_masternode != address(0)) { 291 _denounce(old_masternode, owner); 292 } 293 } 294 295 function _announce_check_free(StorageMasternodeRegistryV1 mn_storage, address masternode) 296 internal view 297 { 298 // SECURITY: there is an option of seizing a foreign MN address at cost of collateral. 299 // The mitigation is regeneration of such address by a victim. 300 // MN should refuse to operate in such condition. 301 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(mn_storage, masternode); 302 require(mninfo.owner == address(0), "Invalid owner"); 303 } 304 305 function _announce_check_ipv4(uint32 ipv4address) internal pure { 306 uint a = ipv4address & 0xFF000000; 307 uint b = ipv4address & 0x00FF0000; 308 uint c = ipv4address & 0x0000FF00; 309 // solium-disable operator-whitespace 310 require( 311 // 127.0.0.0/8 312 (a != (127 << 24)) && 313 // 10.0.0.0/8 314 (a != (10 << 24)) && 315 // 192.168.0.0/16 316 !((a == (192 << 24)) && (b == (168 << 16))) && 317 // 172.16.0.0/12 318 !((a == (172 << 24)) && ((b & 0x00F00000) == (16 << 16))) && 319 // 0.0.0.0/8 320 (a != 0) && 321 // 100.64.0.0/10 322 !((a == (100 << 24)) && ((b & 0x00C00000) == (64 << 16))) && 323 // 169.254.0.0/16 324 !((a == (169 << 24)) && (b == (254 << 16))) && 325 // 198.18.0.0/15 326 !((a == (198 << 24)) && ((b & 0x00FE0000) == (18 << 16))) && 327 // 198.51.100.0/24 328 !((a == (198 << 24)) && (b == (51 << 16)) && (c == (100 << 8))) && 329 // 203.0.113.0/24 330 !((a == (203 << 24)) && (b == (0 << 16)) && (c == (113 << 8))) && 331 // 224.0.0.0/4 332 ((a & 0xF0000000) != (224 << 24)) && 333 // 240.0.0.0/4 334 ((a & 0xF0000000) != (240 << 24)) && 335 // 255.255.255.255/32 336 (ipv4address != 0xFFFFFFFF), 337 "Wrong IP"); 338 // solium-enable operator-whitespace 339 } 340 341 function _announce_insert(StorageMasternodeRegistryV1 mn_storage, address masternode) 342 internal 343 returns(address next, address prev) 344 { 345 // NOTE: always insert as the last - before the current one 346 next = current_masternode; 347 348 if (next != address(0)) { 349 StorageMasternodeRegistryV1.Info memory nextinfo = _mnInfo(mn_storage, next); 350 351 prev = nextinfo.prev; 352 353 // Not effective for the second one, but reliable 354 mn_storage.setMasternodePos( 355 nextinfo.prev, 356 false, address(0), 357 true, masternode 358 ); 359 mn_storage.setMasternodePos( 360 next, 361 true, masternode, 362 false, address(0) 363 ); 364 } else { 365 // The first one 366 current_masternode = masternode; 367 current_payouts = 0; 368 prev = masternode; 369 next = masternode; 370 } 371 } 372 373 //================================= 374 375 function denounce(address masternode) 376 external 377 noReentry 378 { 379 _denounce(masternode, _callerAddress()); 380 } 381 382 function _denounce(address masternode, address owner) internal { 383 // Check masternode ownership, if already registered. 384 //--- 385 StorageMasternodeRegistryV1 mn_storage = v1storage; 386 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(mn_storage, masternode); 387 388 if (mninfo.owner == address(0)) { 389 return; 390 } 391 392 require((owner == mninfo.owner), "Invalid owner"); 393 394 // Remove from list 395 //--- 396 if (mninfo.next == masternode) { 397 // the last one 398 current_masternode = address(0); 399 } else { 400 if (current_masternode == masternode) { 401 current_masternode = mninfo.next; 402 current_payouts = 0; 403 } 404 405 mn_storage.setMasternodePos( 406 mninfo.prev, 407 false, address(0), 408 true, mninfo.next 409 ); 410 mn_storage.setMasternodePos( 411 mninfo.next, 412 true, mninfo.prev, 413 false, address(0) 414 ); 415 } 416 417 // Delete 418 //--- 419 420 mn_announced_collateral -= mninfo.collateral; 421 422 if (mn_status[masternode].seq_payouts > 0) { 423 _deactive_common(masternode, mninfo.collateral); 424 } 425 426 delete mn_status[masternode]; 427 428 mn_storage.deleteMasternode(masternode); 429 --mn_announced; 430 431 //--- 432 emit Denounced(masternode, mninfo.owner); 433 } 434 435 function _deactive_common(address masternode, uint collateral) internal { 436 // Remove from validators 437 address last_validator = validator_list[validator_list.length - 1]; 438 uint validator_index = mn_status[masternode].validator_index; 439 440 mn_status[last_validator].validator_index = validator_index; 441 validator_list[validator_index] = last_validator; 442 validator_list.pop(); 443 444 //-- 445 --mn_active; 446 mn_active_collateral -= collateral; 447 } 448 449 function heartbeat(uint block_number, bytes32 block_hash, uint sw_features) 450 external 451 noReentry 452 { 453 require((block.number - block_number - 1) <= MN_HEARTBEAT_PAST_BLOCKS, "Too old block"); 454 require(blockhash(block_number) == block_hash, "Block mismatch"); 455 456 address payable masternode = _callerAddress(); 457 458 Status storage s = mn_status[masternode]; 459 460 require(_isActive(masternode, s), "Not active"); 461 462 uint hearbeat_delay = block.timestamp - s.last_heartbeat; 463 require(hearbeat_delay > MN_HEARTBEAT_INTERVAL_MIN, "Too early"); 464 465 s.last_heartbeat = block.timestamp; 466 s.sw_features = sw_features; 467 468 emit Heartbeat(masternode); 469 } 470 471 function invalidate(address masternode) 472 external 473 noReentry 474 { 475 address caller = _callerAddress(); 476 require(caller != masternode, "Invalidation for self"); 477 478 uint vote_epoch = block.number / validation_period; 479 480 //--- 481 Status storage cs = mn_status[caller]; 482 require(_isActive(caller, cs), "Not active caller"); 483 require(cs.last_vote_epoch < vote_epoch, "Already invalidated"); 484 require(validationTarget(caller) == masternode, "Invalid target"); 485 486 //--- 487 Status storage s = mn_status[masternode]; 488 489 require(_isActive(masternode, s), "Not active target"); 490 491 //--- 492 cs.last_vote_epoch = vote_epoch; 493 s.invalidations++; 494 495 emit Invalidation(masternode, caller); 496 } 497 498 function validationTarget(address masternode) public view returns(address target) { 499 uint total = validator_list.length; 500 501 uint vperiod = validation_period; 502 uint offset = (block.number / vperiod % (total - 1)) + 1; 503 504 uint target_index = mn_status[masternode].validator_index; 505 target_index = (target_index + offset) % total; 506 507 return validator_list[target_index]; 508 } 509 510 function isActive(address masternode) external view returns(bool) { 511 return _isActive(masternode, mn_status[masternode]); 512 } 513 514 //=== 515 516 function _isActive(address masternode, Status storage mnstatus) internal view returns(bool) { 517 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(v1storage, masternode); 518 return _checkStatus(mnstatus, mninfo) == ValidationStatus.MNActive; 519 } 520 521 function _checkStatus( 522 Status storage mnstatus, 523 StorageMasternodeRegistryV1.Info memory mninfo 524 ) 525 internal view 526 returns(ValidationStatus) 527 { 528 if (mnstatus.seq_payouts == 0) { 529 return ValidationStatus.MNNotActive; 530 } 531 532 if ((block.timestamp - mnstatus.last_heartbeat) >= MN_HEARTBEAT_INTERVAL_MAX) { 533 return ValidationStatus.MNHeartbeat; 534 } 535 536 (uint balance, uint last_block) = IMasternodeToken(address(token_proxy.impl())).balanceInfo(mninfo.owner); 537 538 if (balance != mninfo.collateral) { 539 return ValidationStatus.MNCollaterIssue; 540 } 541 542 if (last_block > mninfo.announced_block) { 543 return ValidationStatus.MNCollaterIssue; 544 } 545 546 return ValidationStatus.MNActive; 547 } 548 549 //=== 550 551 function count() external view 552 returns( 553 uint active, uint total, 554 uint active_collateral, uint total_collateral, 555 uint max_of_all_times 556 ) 557 { 558 active = mn_active; 559 total = mn_announced; 560 active_collateral = mn_active_collateral; 561 total_collateral = mn_announced_collateral; 562 max_of_all_times = mn_ever_collateral; 563 } 564 565 //=== 566 function info(address masternode) external view 567 returns( 568 address owner, uint32 ipv4address, bytes32[2] memory enode, 569 uint collateral, uint announced_block, uint sw_features 570 ) 571 { 572 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(v1storage, masternode); 573 require(mninfo.owner != address(0), "Unknown masternode"); 574 owner = mninfo.owner; 575 ipv4address = mninfo.ipv4address; 576 enode = [ mninfo.enode_0, mninfo.enode_1 ]; 577 collateral = mninfo.collateral; 578 announced_block = mninfo.announced_block; 579 580 sw_features = mn_status[masternode].sw_features; 581 } 582 583 function ownerInfo(address owner) external view 584 returns( 585 address masternode, uint32 ipv4address, bytes32[2] memory enode, 586 uint collateral, uint announced_block, uint sw_features 587 ) 588 { 589 StorageMasternodeRegistryV1 mnstorage = v1storage; 590 591 masternode = mnstorage.owner_masternodes(owner); 592 require(masternode != address(0), "Unknown owner"); 593 594 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(mnstorage, masternode); 595 masternode = masternode; 596 ipv4address = mninfo.ipv4address; 597 enode = [ mninfo.enode_0, mninfo.enode_1 ]; 598 collateral = mninfo.collateral; 599 announced_block = mninfo.announced_block; 600 601 sw_features = mn_status[masternode].sw_features; 602 } 603 604 function _mnInfo( 605 StorageMasternodeRegistryV1 v1info, 606 address masternode 607 ) 608 internal view 609 returns (StorageMasternodeRegistryV1.Info memory mninfo) 610 { 611 // NOTE: no ABIv2 encoding is enabled 612 ( 613 mninfo.announced_block, 614 mninfo.collateral, 615 mninfo.enode_0, 616 mninfo.enode_1, 617 mninfo.owner, 618 mninfo.prev, 619 mninfo.next, 620 mninfo.ipv4address 621 ) = v1info.masternodes(masternode); 622 } 623 624 //=== 625 626 function onCollateralUpdate(address owner) 627 external 628 noReentry 629 { 630 // SECURITY: this is a callback for MasternodeToken, but 631 // it must be safe to be called by ANYONE. 632 633 StorageMasternodeRegistryV1 mn_storage = v1storage; 634 address masternode = mn_storage.owner_masternodes(owner); 635 636 if (masternode == address(0)) { 637 return; 638 } 639 640 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(v1storage, masternode); 641 ValidationStatus check = _checkStatus(mn_status[masternode], mninfo); 642 643 if (check == ValidationStatus.MNCollaterIssue) { 644 // Only if collateral issue! 645 _denounce(masternode, owner); 646 } 647 } 648 649 function enumerate() 650 external view 651 returns(address[] memory masternodes) 652 { 653 // NOTE: it should be OK for 0 654 masternodes = new address[](mn_announced); 655 address curr_mn = current_masternode; 656 657 if (curr_mn == address(0)) { 658 return masternodes; 659 } 660 661 address next = curr_mn; 662 StorageMasternodeRegistryV1.Info memory mninfo; 663 uint i = 0; 664 665 do { 666 masternodes[i] = next; 667 mninfo = _mnInfo(v1storage, next); 668 next = mninfo.next; 669 ++i; 670 } while (next != curr_mn); 671 } 672 673 function enumerateActive() 674 external view 675 returns(address[] memory masternodes) 676 { 677 // NOTE: this API is targeted at fast consensus execution 678 masternodes = new address[](mn_active); 679 680 for (uint i = 0; i < masternodes.length; ++i) { 681 masternodes[i] = validator_list[i]; 682 } 683 } 684 685 // IGovernedContract 686 //--------------------------------- 687 function _destroy(IGovernedContract _newImpl) internal { 688 v1storage.setOwner(_newImpl); 689 } 690 691 // IBlockReward 692 //--------------------------------- 693 function reward() 694 external payable 695 noReentry 696 { 697 // NOTE: ensure to move of remaining from the previous times to Treasury 698 //--- 699 uint diff = address(this).balance - msg.value; 700 701 if (int(diff) > 0) { 702 IBlockReward treasury = IBlockReward(address(treasury_proxy.impl())); 703 treasury.reward.value(diff)(); 704 } 705 706 //--- 707 // SECURITY: do processing only when reward is exactly as expected 708 if (msg.value == REWARD_MASTERNODE_V1) { 709 // SECURITY: this check is essential against Masternode skip attacks! 710 require(last_block_number < block.number, "Call outside of governance!"); 711 last_block_number = last_block_number; 712 713 assert(gasleft() > GAS_RESERVE); 714 assert(msg.value == address(this).balance); 715 716 // solium-disable-next-line no-empty-blocks 717 while ((gasleft() > GAS_RESERVE) && !_reward()) {} 718 } 719 } 720 721 function _reward() internal returns(bool) { 722 //--- 723 address masternode = current_masternode; 724 uint payouts = current_payouts; 725 726 if (masternode == address(0)) { 727 return true; 728 } 729 730 StorageMasternodeRegistryV1.Info memory mninfo = _mnInfo(v1storage, masternode); 731 732 Status storage mnstatus = mn_status[masternode]; 733 uint invalidations = mnstatus.invalidations; 734 uint invalidation_since = mnstatus.invalidation_since; 735 ++payouts; 736 737 if (payouts < mnstatus.seq_payouts) { 738 current_payouts = payouts; 739 } else { 740 mnstatus.invalidations = 0; 741 mnstatus.invalidation_since = block.number; 742 current_masternode = mninfo.next; 743 current_payouts = 0; 744 } 745 746 // Reward logic 747 //--- 748 ValidationStatus status = _checkStatus(mnstatus, mninfo); 749 750 if (status == ValidationStatus.MNActive) { 751 // solium-disable security/no-send 752 if (!_canReward(invalidations, invalidation_since) || 753 mninfo.owner.send(msg.value) 754 ) { 755 return true; 756 } 757 // solium-enable security/no-send 758 } 759 760 // When not valid 761 //--- 762 if (status == ValidationStatus.MNCollaterIssue) { 763 // Immediate 764 _denounce(masternode, mninfo.owner); 765 } else if (mnstatus.seq_payouts > 0) { 766 // Mark as inactive for later auto-cleanup 767 mnstatus.seq_payouts = 0; 768 mnstatus.inactive_since = block.timestamp; 769 _deactive_common(masternode, mninfo.collateral); 770 current_masternode = mninfo.next; 771 current_payouts = 0; 772 773 emit Deactivated(masternode); 774 } else if ((block.timestamp - mnstatus.inactive_since) > cleanup_period) { 775 // Auto-cleanup 776 _denounce(masternode, mninfo.owner); 777 } 778 779 return false; 780 } 781 782 function _canReward(uint invalidations, uint invalidation_since) internal view returns(bool) { 783 if (mn_active < require_validation) { 784 return true; 785 } 786 787 uint threshold = block.number - invalidation_since; 788 threshold = (threshold / validation_period) + 1; 789 threshold /= 2; 790 791 return (invalidations < threshold); 792 } 793 794 //=== 795 796 function getReward(uint _blockNumber) 797 external view 798 returns(uint amount) 799 { 800 ITreasury treasury = ITreasury(address(treasury_proxy.impl())); 801 802 if ((_blockNumber > 0) && !treasury.isSuperblock(_blockNumber)) { 803 amount = REWARD_MASTERNODE_V1; 804 } 805 } 806 807 // Safety 808 //--------------------------------- 809 function () external payable { 810 revert("Not supported"); 811 } 812 }