Skip to content

Commit

Permalink
v0.6.4-testnet (#290)
Browse files Browse the repository at this point in the history
  • Loading branch information
nxqbao authored Sep 29, 2023
2 parents e414ad3 + 1208da9 commit e6efc36
Show file tree
Hide file tree
Showing 13 changed files with 1,547 additions and 134 deletions.
23 changes: 23 additions & 0 deletions contracts/interfaces/IProfile.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,23 @@ interface IProfile {
event ProfileAdded(address indexed id);
/// @dev Event emitted when a address in a profile is changed.
event ProfileAddressChanged(address indexed id, RoleAccess indexed addressType);
/// @dev Event emitted when the pubkey of the `id` is changed.
event PubkeyChanged(address indexed id, bytes pubkey);

/// @dev Error of already existed profile.
error ErrExistentProfile();
/// @dev Error of non existed profile.
error ErrNonExistentProfile();
/// @dev Error when create a new profile whose id and consensus are not identical.
error ErrIdAndConsensusDiffer();
/**
* @dev Error when there is a duplicated info of `value`, which is uin256-padding value of any address or hash of public key,
* and with value type of `infoType`.
*/
error ErrDuplicatedInfo(RoleAccess infoType, uint256 value);
error ErrDuplicatedPubkey(bytes pubkey);
error ErrZeroAddress(RoleAccess infoType);
error ErrZeroPubkey();

/// @dev Getter to query full `profile` from `id` address.
function getId2Profile(address id) external view returns (CandidateProfile memory profile);
Expand All @@ -57,4 +69,15 @@ interface IProfile {
*/

function registerProfile(CandidateProfile memory profile) external;

/**
* @notice The candidate admin changes the public key.
*
* @dev Requirements:
* - The profile must be existed.
* - Only user with candidate admin role can call this method.
* - New public key must not be duplicated.
*/

function changePubkey(address id, bytes memory pubkey) external;
}
83 changes: 81 additions & 2 deletions contracts/ronin/profile/Profile.sol
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// SPDX-License-Identifier: MIT

import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "../../interfaces/validator/ICandidateManager.sol";
import "../../interfaces/validator/IRoninValidatorSet.sol";
import "../../interfaces/IProfile.sol";
import { ErrUnauthorized, RoleAccess } from "../../utils/CommonErrors.sol";
import "./ProfileStorage.sol";
import { ContractType } from "../../utils/ContractType.sol";
import "./ProfileHandler.sol";

pragma solidity ^0.8.9;

contract Profile is IProfile, ProfileStorage, Initializable {
contract Profile is IProfile, ProfileHandler, Initializable {
constructor() {
_disableInitializers();
}
Expand All @@ -17,6 +19,68 @@ contract Profile is IProfile, ProfileStorage, Initializable {
_setContract(ContractType.VALIDATOR, validatorContract);
}

function migrateTestnet() external {
require(block.chainid == 2021, "mismatch chainID");
require(msg.sender == 0x968D0Cd7343f711216817E617d3f92a23dC91c07, "not testnet admin");

CandidateProfile storage _profile;

address[10] memory consensusList = [
0xCaba9D9424D6bAD99CE352A943F59279B533417a,
0x9f1Abc67beA4db5560371fF3089F4Bfe934c36Bc,
0xA85ddDdCeEaB43DccAa259dd4936aC104386F9aa,
0xAcf8Bf98D1632e602d0B1761771049aF21dd6597,
0xE9bf2A788C27dADc6B169d52408b710d267b9bff,
0xD086D2e3Fac052A3f695a4e8905Ce1722531163C,
// 0x9687e8C41fa369aD08FD278a43114C4207856a61, // missing
0xa325Fd3a2f4f5CafE2c151eE428b5CeDeD628193,
0x9422d990AcDc3f2b3AA3B97303aD3060F09d7ffC,
0xc3C97512421BF3e339E9fd412f18584e53138bFA,
0x78fD38faa30ea66702cc39383D2E84f9a4A56fA6
];

for (uint i; i < consensusList.length; i++) {
_migrateTestnetHelper(consensusList[i]);
}

{
_profile = _getId2ProfileHelper(0xCaba9D9424D6bAD99CE352A943F59279B533417a);
_setGovernor(_profile, 0xb033ba62EC622dC54D0ABFE0254e79692147CA26);
}
{
_profile = _getId2ProfileHelper(0x9f1Abc67beA4db5560371fF3089F4Bfe934c36Bc);
_setGovernor(_profile, 0x087D08e3ba42e64E3948962dd1371F906D1278b9);
}
{
_profile = _getId2ProfileHelper(0xA85ddDdCeEaB43DccAa259dd4936aC104386F9aa);
_setGovernor(_profile, 0x52ec2e6BBcE45AfFF8955Da6410bb13812F4289F);
}
{
_profile = _getId2ProfileHelper(0xAcf8Bf98D1632e602d0B1761771049aF21dd6597);
_setGovernor(_profile, 0xd24D87DDc1917165435b306aAC68D99e0F49A3Fa);
}
}

function migrateTestnetManual(address consensus, address governor) external {
require(block.chainid == 2021, "mismatch chainID");
require(msg.sender == 0x968D0Cd7343f711216817E617d3f92a23dC91c07, "not testnet admin");

_migrateTestnetHelper(consensus);
if (governor != address(0)) {
CandidateProfile storage _profile = _getId2ProfileHelper(consensus);
_setGovernor(_profile, governor);
}
}

function _migrateTestnetHelper(address consensus) internal {
CandidateProfile storage _profile = _getId2ProfileHelper(consensus);
ICandidateManager.ValidatorCandidate memory info = IRoninValidatorSet(getContract(ContractType.VALIDATOR))
.getCandidateInfo(consensus);
_setConsensus(_profile, consensus);
_setAdmin(_profile, info.admin);
_setTreasury(_profile, payable(info.treasuryAddr));
}

/**
* @inheritdoc IProfile
*/
Expand All @@ -37,13 +101,28 @@ contract Profile is IProfile, ProfileStorage, Initializable {
* @inheritdoc IProfile
*/
function registerProfile(CandidateProfile memory profile) external {
if (profile.id != profile.consensus) revert ErrIdAndConsensusDiffer();

CandidateProfile storage _profile = _id2Profile[profile.id];
if (_profile.id != address(0)) revert ErrExistentProfile();
if (
msg.sender != profile.admin ||
!IRoninValidatorSet(getContract(ContractType.VALIDATOR)).isCandidateAdmin(profile.consensus, profile.admin)
) revert ErrUnauthorized(msg.sig, RoleAccess.ADMIN);
_checkDuplicatedInRegistry(profile);

_addNewProfile(_profile, profile);
}

/**
* @inheritdoc IProfile
*/
function changePubkey(address id, bytes memory pubkey) external {
CandidateProfile storage _profile = _getId2ProfileHelper(id);
if (msg.sender != _profile.admin) revert ErrUnauthorized(msg.sig, RoleAccess.ADMIN);
_checkNonDuplicatedPubkey(pubkey);
_setPubkey(_profile, pubkey);

emit PubkeyChanged(id, pubkey);
}
}
36 changes: 36 additions & 0 deletions contracts/ronin/profile/ProfileHandler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

import "../../utils/RoleAccess.sol";
import { ProfileStorage } from "./ProfileStorage.sol";

abstract contract ProfileHandler is ProfileStorage {
/**
* @dev Checks each element in the new profile and reverts if there is duplication with any existing profile.
*/
function _checkDuplicatedInRegistry(CandidateProfile memory profile) internal view {
_checkNonZeroAndNonDuplicated(RoleAccess.CONSENSUS, profile.consensus);
_checkNonZeroAndNonDuplicated(RoleAccess.CANDIDATE_ADMIN, profile.admin);
_checkNonZeroAndNonDuplicated(RoleAccess.TREASURY, profile.treasury);
_checkNonDuplicated(RoleAccess.TREASURY, profile.governor);
_checkNonDuplicatedPubkey(profile.pubkey);
}

function _checkNonZeroAndNonDuplicated(RoleAccess addressType, address addr) internal view {
if (addr == address(0)) revert ErrZeroAddress(addressType);
_checkNonDuplicated(addressType, addr);
}

function _checkNonDuplicated(RoleAccess addressType, address addr) internal view {
if (_registry[uint256(uint160(addr))]) {
revert ErrDuplicatedInfo(addressType, uint256(uint160(addr)));
}
}

function _checkNonDuplicatedPubkey(bytes memory pubkey) internal view {
if (_registry[_hashPubkey(pubkey)]) {
revert ErrDuplicatedPubkey(pubkey);
}
}
}
58 changes: 51 additions & 7 deletions contracts/ronin/profile/ProfileStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,72 @@ import { IProfile } from "../../interfaces/IProfile.sol";
abstract contract ProfileStorage is IProfile, HasContracts {
/// @dev Mapping from id address => candidate profile.
mapping(address => CandidateProfile) internal _id2Profile;
/**
* @dev Mapping from any address or keccak256(pubkey) => whether it is already registered.
* This registry can only be toggled to `true` and NOT vice versa. All registered values
* cannot be reused.
*/
mapping(uint256 => bool) internal _registry;
/// @dev Upgradeable gap.
bytes32[50] __gap;
bytes32[49] __gap;

/**
* @dev Add a profile from memory to storage.
*/
function _addNewProfile(CandidateProfile storage _profile, CandidateProfile memory newProfile) internal {
_profile.id = newProfile.id;
_profile.consensus = newProfile.consensus;
_profile.admin = newProfile.admin;
_profile.treasury = newProfile.treasury;
_profile.governor = newProfile.governor;
_profile.pubkey = newProfile.pubkey;

_setConsensus(_profile, newProfile.consensus);
_setAdmin(_profile, newProfile.admin);
_setTreasury(_profile, newProfile.treasury);
_setGovernor(_profile, newProfile.governor);
_setPubkey(_profile, newProfile.pubkey);

emit ProfileAdded(newProfile.id);
}

function _setConsensus(CandidateProfile storage _profile, address consensus) internal {
_profile.consensus = consensus;
_registry[uint256(uint160(consensus))] = true;
}

function _setAdmin(CandidateProfile storage _profile, address admin) internal {
_profile.admin = admin;
_registry[uint256(uint160(admin))] = true;
}

function _setTreasury(CandidateProfile storage _profile, address payable treasury) internal {
_profile.treasury = treasury;
_registry[uint256(uint160(address(treasury)))] = true;
}

/**
* @dev Get an existed profile struct from id. Revert if the profile does not exists.
* @dev Allow to registry a profile without governor address since not all validators are governing validators.
*/
function _setGovernor(CandidateProfile storage _profile, address governor) internal {
_profile.governor = governor;
if (governor != address(0)) {
_registry[uint256(uint160(governor))] = true;
}
}

function _setPubkey(CandidateProfile storage _profile, bytes memory pubkey) internal {
_profile.pubkey = pubkey;
_registry[_hashPubkey(pubkey)] = true;
}

/**
* @dev Get an existed profile struct from `id`. Revert if the profile does not exists.
*/
function _getId2ProfileHelper(address id) internal view returns (CandidateProfile storage _profile) {
_profile = _id2Profile[id];
if (_profile.id == address(0)) revert ErrNonExistentProfile();
}

/**
* @dev Returns hash of a public key.
*/
function _hashPubkey(bytes memory pubkey) internal pure returns (uint256) {
return uint256(keccak256(pubkey));
}
}
4 changes: 3 additions & 1 deletion contracts/utils/RoleAccess.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ enum RoleAccess {
/* 5 */ WITHDRAWAL_MIGRATOR,
/* 6 */ __DEPRECATED_BRIDGE_OPERATOR,
/* 7 */ BLOCK_PRODUCER,
/* 8 */ VALIDATOR_CANDIDATE
/* 8 */ VALIDATOR_CANDIDATE,
/* 9 */ CONSENSUS,
/* 10 */ TREASURY
}
Loading

0 comments on commit e6efc36

Please sign in to comment.