github.com/klaytn/klaytn@v1.12.1/contracts/system_contracts/kip113/KIP113.sol (about) 1 // Copyright 2023 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The klaytn library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 // SPDX-License-Identifier: LGPL-3.0-only 18 pragma solidity ^0.8.18; 19 20 import "./IKIP113.sol"; 21 import "./IAddressBook.sol"; 22 import "../lib/Initializable.sol"; 23 import "../lib/UUPSUpgradeable.sol"; 24 import "../lib/OwnableUpgradeable.sol"; 25 26 contract KIP113 is Initializable, UUPSUpgradeable, OwnableUpgradeable, IKIP113 { 27 IAddressBook public constant abook = IAddressBook(0x0000000000000000000000000000000000000400); 28 bytes32 public constant ZERO48HASH = 0xc980e59163ce244bb4bb6211f48c7b46f88a4f40943e84eb99bdc41e129bd293; // keccak256(hex"00"*48) 29 bytes32 public constant ZERO96HASH = 0x46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21; // keccak256(hex"00"*96) 30 31 address[] public allNodeIds; 32 mapping(address => BlsPublicKeyInfo) public record; // cnNodeId => BlsPublicKeyInfo 33 34 event Registered(address cnNodeId, bytes publicKey, bytes pop); 35 event Unregistered(address cnNodeId, bytes publicKey, bytes pop); 36 37 modifier onlyValidPublicKey(bytes calldata publicKey) { 38 require(publicKey.length == 48, "Public key must be 48 bytes"); 39 require(keccak256(publicKey) != ZERO48HASH, "Public key cannot be zero"); 40 // TODO: verify more with EIP-2537 41 _; 42 } 43 44 modifier onlyValidPop(bytes calldata pop) { 45 require(pop.length == 96, "Pop must be 96 bytes"); 46 require(keccak256(pop) != ZERO96HASH, "Pop cannot be zero"); 47 // TODO: verify more with EIP-2537 48 _; 49 } 50 51 /// @custom:oz-upgrades-unsafe-allow constructor 52 constructor() { 53 _disableInitializers(); 54 } 55 56 function initialize() public initializer { 57 __Ownable_init(); 58 __UUPSUpgradeable_init(); 59 } 60 61 function register( 62 address cnNodeId, 63 bytes calldata publicKey, 64 bytes calldata pop 65 ) external virtual onlyOwner onlyValidPublicKey(publicKey) onlyValidPop(pop) { 66 require(isCN(cnNodeId), "cnNodeId is not in AddressBook"); 67 if (record[cnNodeId].publicKey.length == 0) { 68 allNodeIds.push(cnNodeId); 69 } 70 71 record[cnNodeId] = BlsPublicKeyInfo(publicKey, pop); 72 emit Registered(cnNodeId, publicKey, pop); 73 } 74 75 function unregister(address cnNodeId) external virtual onlyOwner { 76 require(!isCN(cnNodeId), "CN is still in AddressBook"); 77 require(record[cnNodeId].publicKey.length != 0, "CN is not registered"); 78 79 _removeCnNodeId(cnNodeId); 80 emit Unregistered(cnNodeId, record[cnNodeId].publicKey, record[cnNodeId].pop); 81 delete record[cnNodeId]; 82 } 83 84 function _removeCnNodeId(address cnNodeId) private { 85 for (uint256 i = 0; i < allNodeIds.length; i++) { 86 if (allNodeIds[i] == cnNodeId) { 87 allNodeIds[i] = allNodeIds[allNodeIds.length - 1]; 88 allNodeIds.pop(); 89 return; 90 } 91 } 92 } 93 94 function getAllBlsInfo() 95 external 96 view 97 virtual 98 returns (address[] memory nodeIdList, BlsPublicKeyInfo[] memory pubkeyList) 99 { 100 nodeIdList = new address[](allNodeIds.length); 101 pubkeyList = new BlsPublicKeyInfo[](allNodeIds.length); 102 103 for (uint256 i = 0; i < nodeIdList.length; i++) { 104 nodeIdList[i] = allNodeIds[i]; 105 pubkeyList[i] = record[allNodeIds[i]]; 106 } 107 } 108 109 function isCN(address target) internal view virtual returns (bool) { 110 try abook.getCnInfo(target) { 111 return true; 112 } catch { 113 return false; 114 } 115 } 116 117 function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} 118 }