Skip to content

Commit

Permalink
Adjust multi-chain logic around mining skill id
Browse files Browse the repository at this point in the history
  • Loading branch information
area committed Mar 4, 2024
1 parent cfafdec commit 0b4f19b
Show file tree
Hide file tree
Showing 47 changed files with 347 additions and 161 deletions.
15 changes: 15 additions & 0 deletions contracts/colony/Colony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,18 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP
IColonyNetwork(colonyNetworkAddress).setColonyBridgeAddress(_bridgeAddress);
}

function initialiseReputationMining(
uint256 miningChainId,
bytes32 newHash,
uint256 newNLeaves
) public stoppable auth {
IColonyNetwork(colonyNetworkAddress).initialiseReputationMining(
miningChainId,
newHash,
newNLeaves
);
}

function addExtensionToNetwork(bytes32 _extensionId, address _resolver) public stoppable auth {
IColonyNetwork(colonyNetworkAddress).addExtensionToNetwork(_extensionId, _resolver);
}
Expand Down Expand Up @@ -329,6 +341,9 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP

sig = bytes4(keccak256("setColonyBridgeAddress(address)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true);

sig = bytes4(keccak256("initialiseReputationMining(uint256,bytes32,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true);
}

function getMetatransactionNonce(address _user) public view override returns (uint256 nonce) {
Expand Down
1 change: 1 addition & 0 deletions contracts/colony/ColonyAuthority.sol
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ contract ColonyAuthority is CommonAuthority {

// Added in colony vxxx
addRoleCapability(ROOT_ROLE, "setColonyBridgeAddress(address)");
addRoleCapability(ROOT_ROLE, "initialiseReputationMining(uint256,bytes32,uint256)");
}

function addRoleCapability(uint8 role, bytes memory sig) private {
Expand Down
13 changes: 13 additions & 0 deletions contracts/colony/IMetaColony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,17 @@ interface IMetaColony is IColony {
// @notice Called to set the address of the colony bridge contract
/// @param _bridgeAddress The address of the bridge
function setColonyBridgeAddress(address _bridgeAddress) external;

/// @notice Creates initial inactive reputation mining cycle.
/// @dev Only callable from metacolony
/// @param miningChainId The chainId of the chain the mining cycle is being created on
/// Can either be this chain or another chain, and the function will behave differently depending
/// on which is the case.
/// @param newHash The root hash of the reputation state tree
/// @param newNLeaves The number of leaves in the state tree
function initialiseReputationMining(
uint256 miningChainId,
bytes32 newHash,
uint256 newNLeaves
) external;
}
4 changes: 2 additions & 2 deletions contracts/colonyNetwork/ColonyNetwork.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall
colonyVersionResolver[_version] = _resolver;
currentColonyVersion = _version;

if (!isMiningChain()) {
skillCount = toRootSkillId(getChainId());
if (!isXdai()) {
skillCount = toRootSkillId(block.chainid);
}

emit ColonyNetworkInitialised(_resolver);
Expand Down
6 changes: 3 additions & 3 deletions contracts/colonyNetwork/ColonyNetworkAuction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,15 @@ contract DutchAuction is DSMath, MultiChain, BasicMetaTransaction {
finalized = true;

// Burn all CLNY received
if (isXdai()) {
if (isMainnet()) {
clnyToken.burn(receivedTotal);
} else {
// On Xdai, we can't burn bridged tokens
// so let's send them to the metacolony for now.
require(
clnyToken.transfer(metaColonyAddress, receivedTotal),
"colony-network-transfer-failed"
);
} else {
clnyToken.burn(receivedTotal);
}
emit AuctionFinalized(finalPrice);
}
Expand Down
6 changes: 3 additions & 3 deletions contracts/colonyNetwork/ColonyNetworkDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ contract ColonyNetworkDeployer is ColonyNetworkStorage {
metaColony = createColony(_tokenAddress, currentColonyVersion, "", "");

// Add the special mining skill
if (isMiningChain()) {
reputationMiningSkillId = IColonyNetwork(address(this)).addSkill(skillCount - 1);
}
// if (isMiningChain()) {
// reputationMiningSkillId = IColonyNetwork(address(this)).addSkill(skillCount - 1);
// }

emit MetaColonyCreated(metaColony, _tokenAddress, skillCount);
}
Expand Down
45 changes: 37 additions & 8 deletions contracts/colonyNetwork/ColonyNetworkMining.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { ITokenLocking } from "./../tokenLocking/ITokenLocking.sol";
import { ColonyNetworkStorage } from "./ColonyNetworkStorage.sol";
import { IMetaColony } from "./../colony/IMetaColony.sol";
import { IColonyBridge } from "./../bridging/IColonyBridge.sol";
import { IColonyNetwork } from "./IColonyNetwork.sol";
import { ColonyDataTypes } from "./../colony/ColonyDataTypes.sol";

contract ColonyNetworkMining is ColonyNetworkStorage {
// TODO: Can we handle a dispute regarding the very first hash that should be set?
Expand Down Expand Up @@ -145,31 +147,56 @@ contract ColonyNetworkMining is ColonyNetworkStorage {
}

// slither-disable-next-line reentrancy-no-eth
function initialiseReputationMining() public onlyMiningChain stoppable {
function initialiseReputationMining(
uint256 _reputationMiningChainId,
bytes32 _newHash,
uint256 _newNLeaves
) public stoppable calledByMetaColony {
require(
inactiveReputationMiningCycle == address(0x0),
(reputationMiningChainId == 0) || // Either it's the first time setting it
// Or we're moving from a chain that's not this chain to another chain that's not this one
(reputationMiningChainId != block.chainid && _reputationMiningChainId != block.chainid),
"colony-reputation-mining-already-initialised"
);
reputationMiningChainId = _reputationMiningChainId;

if (reputationMiningChainId != block.chainid) {
// Reputation mining is on another chain, so we will need to set up the bridge
// But we're done here for now other than making sure everything is unset
reputationMiningSkillId = 0;
inactiveReputationMiningCycle = address(0x0);
activeReputationMiningCycle = address(0x0);
return;
}

address clnyToken = IMetaColony(metaColony).getToken();
require(clnyToken != address(0x0), "colony-reputation-mining-clny-token-invalid-address");

// Add the special mining skill
ColonyDataTypes.Domain memory d = IMetaColony(metaColony).getDomain(1);

reputationMiningSkillId = IColonyNetwork(address(this)).addSkill(d.skillId);

EtherRouter e = new EtherRouter();
e.setResolver(miningCycleResolver);
inactiveReputationMiningCycle = address(e);
IReputationMiningCycle(inactiveReputationMiningCycle).initialise(tokenLocking, clnyToken);

emit ReputationMiningInitialised(inactiveReputationMiningCycle);

reputationRootHash = _newHash;
reputationRootHashNLeaves = _newNLeaves;

emit ReputationRootHashSet(_newHash, _newNLeaves, newAddressArray(), 0);

startNextCycle();
}

// slither-disable-next-line reentrancy-no-eth
function startNextCycle() public onlyMiningChain stoppable {
address clnyToken = IMetaColony(metaColony).getToken();
require(clnyToken != address(0x0), "colony-reputation-mining-clny-token-invalid-address");
require(activeReputationMiningCycle == address(0x0), "colony-reputation-mining-still-active");
require(
inactiveReputationMiningCycle != address(0x0),
"colony-reputation-mining-not-initialised"
);
// Inactive now becomes active
activeReputationMiningCycle = inactiveReputationMiningCycle;
IReputationMiningCycle(activeReputationMiningCycle).resetWindow();
Expand Down Expand Up @@ -300,7 +327,7 @@ contract ColonyNetworkMining is ColonyNetworkStorage {
ITokenLocking(tokenLocking).transfer(clnyToken, amount, _recipient, true);
}

function stakeForMining(uint256 _amount) public onlyMiningChain stoppable {
function stakeForMining(uint256 _amount) public onlyMiningChainOrDuringSetup stoppable {
address clnyToken = IMetaColony(metaColony).getToken();

ITokenLocking(tokenLocking).approveStake(msgSender(), _amount, clnyToken);
Expand Down Expand Up @@ -381,7 +408,9 @@ contract ColonyNetworkMining is ColonyNetworkStorage {
// slither-disable-end divide-before-multiply
}

function setMiningResolver(address _miningResolver) public onlyMiningChain stoppable auth {
function setMiningResolver(
address _miningResolver
) public stoppable onlyMiningChainOrDuringSetup auth {
require(_miningResolver != address(0x0), "colony-mining-resolver-cannot-be-zero");

miningCycleResolver = _miningResolver;
Expand Down
30 changes: 15 additions & 15 deletions contracts/colonyNetwork/ColonyNetworkSkills.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ contract ColonyNetworkSkills is ColonyNetworkStorage, Multicall {
// Build the transaction we're going to send to the bridge to register the
// creation of this skill on the home chain
uint256 parentSkillId = skills[_skillId].parents.length == 0
? (toRootSkillId(getChainId()))
? (toRootSkillId(block.chainid))
: skills[_skillId].parents[0];

bytes memory payload = abi.encodeWithSignature(
Expand All @@ -118,7 +118,7 @@ contract ColonyNetworkSkills is ColonyNetworkStorage, Multicall {

// Try-catch does not catch if the bridge is not a contract, so we need to check that first
if (isContract(colonyBridgeAddress)) {
try IColonyBridge(colonyBridgeAddress).sendMessage(MINING_CHAIN_ID, payload) returns (
try IColonyBridge(colonyBridgeAddress).sendMessage(reputationMiningChainId, payload) returns (
bool success
) {
if (success) {
Expand All @@ -137,13 +137,13 @@ contract ColonyNetworkSkills is ColonyNetworkStorage, Multicall {
) public stoppable onlyNotMiningChain {
require(colonyBridgeAddress != address(0x0), "colony-network-foreign-bridge-not-set");
require(
pendingReputationUpdates[getChainId()][_colony][_updateNumber - 1].colony == address(0x00),
pendingReputationUpdates[block.chainid][_colony][_updateNumber - 1].colony == address(0x00),
"colony-network-not-next-pending-update"
);

PendingReputationUpdate storage pendingUpdate = pendingReputationUpdates[getChainId()][_colony][
_updateNumber
];
PendingReputationUpdate storage pendingUpdate = pendingReputationUpdates[block.chainid][
_colony
][_updateNumber];
require(pendingUpdate.colony != address(0x00), "colony-network-update-does-not-exist");

int256 updateAmount = decayReputation(pendingUpdate.amount, pendingUpdate.timestamp);
Expand All @@ -158,11 +158,11 @@ contract ColonyNetworkSkills is ColonyNetworkStorage, Multicall {
_updateNumber
);

delete pendingReputationUpdates[getChainId()][_colony][_updateNumber];
delete pendingReputationUpdates[block.chainid][_colony][_updateNumber];

// Try-catch does not catch if the bridge is not a contract, so we need to check that first
if (isContract(colonyBridgeAddress)) {
try IColonyBridge(colonyBridgeAddress).sendMessage(MINING_CHAIN_ID, payload) returns (
try IColonyBridge(colonyBridgeAddress).sendMessage(reputationMiningChainId, payload) returns (
bool success
) {
if (success) {
Expand Down Expand Up @@ -460,26 +460,26 @@ contract ColonyNetworkSkills is ColonyNetworkStorage, Multicall {
// TODO: Maybe force to be set on deployment?
require(colonyBridgeAddress != address(0x0), "colony-network-foreign-bridge-not-set");
address colonyAddress = msgSender();
reputationUpdateCount[getChainId()][colonyAddress] += 1;
reputationUpdateCount[block.chainid][colonyAddress] += 1;
// Build the transaction we're going to send to the bridge
bytes memory payload = abi.encodeWithSignature(
"addReputationUpdateLogFromBridge(address,address,int256,uint256,uint256)",
colonyAddress,
_user,
_amount,
_skillId,
reputationUpdateCount[getChainId()][colonyAddress]
reputationUpdateCount[block.chainid][colonyAddress]
);

// Try-catch does not catch if the bridge is not a contract, so we need to check that first
if (isContract(colonyBridgeAddress)) {
try IColonyBridge(colonyBridgeAddress).sendMessage(MINING_CHAIN_ID, payload) returns (
try IColonyBridge(colonyBridgeAddress).sendMessage(reputationMiningChainId, payload) returns (
bool success
) {
if (success) {
emit ReputationUpdateSentToBridge(
colonyAddress,
reputationUpdateCount[getChainId()][colonyAddress]
reputationUpdateCount[block.chainid][colonyAddress]
);
return;
// Every other type of failure will drop through and store
Expand All @@ -495,11 +495,11 @@ contract ColonyNetworkSkills is ColonyNetworkStorage, Multicall {
msgSender(),
block.timestamp
);
pendingReputationUpdates[getChainId()][colonyAddress][
reputationUpdateCount[getChainId()][colonyAddress]
pendingReputationUpdates[block.chainid][colonyAddress][
reputationUpdateCount[block.chainid][colonyAddress]
] = pendingReputationUpdate;

emit ReputationUpdateStored(colonyAddress, reputationUpdateCount[getChainId()][colonyAddress]);
emit ReputationUpdateStored(colonyAddress, reputationUpdateCount[block.chainid][colonyAddress]);
}

// Mining cycle decay constants
Expand Down
27 changes: 26 additions & 1 deletion contracts/colonyNetwork/ColonyNetworkStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ contract ColonyNetworkStorage is ColonyNetworkDataTypes, DSMath, CommonStorage,

mapping(uint256 => uint256) bridgeCurrentRootHashNonces; // Storage slot 48

uint256 reputationMiningChainId; // Storage slot 49

// Modifiers

modifier calledByColony() {
Expand All @@ -152,7 +154,7 @@ contract ColonyNetworkStorage is ColonyNetworkDataTypes, DSMath, CommonStorage,

modifier skillExists(uint256 skillId) {
require(skillCount >= skillId, "colony-invalid-skill-id");
require(isMiningChain() || toChainId(skillId) == getChainId(), "colony-invalid-skill-id");
require(toChainId(skillId) == block.chainid || isXdai(), "colony-invalid-skill-id");
_;
}

Expand All @@ -161,6 +163,25 @@ contract ColonyNetworkStorage is ColonyNetworkDataTypes, DSMath, CommonStorage,
_;
}

modifier onlyMiningChain() {
require(reputationMiningChainId != 0, "colony-reputation-mining-not-initialised");
require(isMiningChain(), "colony-only-valid-on-mining-chain");
_;
}

modifier onlyMiningChainOrDuringSetup() {
require(
isMiningChain() || reputationMiningChainId == 0,
"colony-only-valid-on-mining-chain-or-during-setup"
);
_;
}

modifier onlyNotMiningChain() {
require(!isMiningChain(), "colony-only-valid-not-on-mining-chain");
_;
}

// Internal functions

function toRootSkillId(uint256 _chainId) internal pure returns (uint256) {
Expand All @@ -171,4 +192,8 @@ contract ColonyNetworkStorage is ColonyNetworkDataTypes, DSMath, CommonStorage,
function toChainId(uint256 _skillId) internal pure returns (uint256) {
return _skillId >> 128;
}

function isMiningChain() internal view returns (bool) {
return block.chainid == reputationMiningChainId;
}
}
12 changes: 11 additions & 1 deletion contracts/colonyNetwork/IColonyNetwork.sol
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,17 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery, IBasicMetaTransac
function startNextCycle() external;

/// @notice Creates initial inactive reputation mining cycle.
function initialiseReputationMining() external;
/// @dev Only callable from metacolony
/// @param miningChainId The chainId of the chain the mining cycle is being created on
/// Can either be this chain or another chain, and the function will behave differently depending
/// on which is the case.
/// @param newHash The root hash of the reputation state tree
/// @param newNLeaves The number of leaves in the state tree
function initialiseReputationMining(
uint256 miningChainId,
bytes32 newHash,
uint256 newNLeaves
) external;

/// @notice Get the root hash of the current reputation state tree.
/// @return rootHash The current Reputation Root Hash
Expand Down
2 changes: 1 addition & 1 deletion contracts/common/BasicMetaTransaction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ abstract contract BasicMetaTransaction is DSMath, MetaTransactionMsgSender, Mult
uint8 _sigV
) public payable returns (bytes memory) {
require(
verify(_user, getMetatransactionNonce(_user), getChainId(), _payload, _sigR, _sigS, _sigV),
verify(_user, getMetatransactionNonce(_user), block.chainid, _payload, _sigR, _sigS, _sigV),
"metatransaction-signer-signature-mismatch"
);
incrementMetatransactionNonce(_user);
Expand Down
Loading

0 comments on commit 0b4f19b

Please sign in to comment.