diff --git a/.solcover.crosschain.js b/.solcover.crosschain.js index 33ec45fc3f..8425f70891 100644 --- a/.solcover.crosschain.js +++ b/.solcover.crosschain.js @@ -3,6 +3,8 @@ const log = console.log; const { execSync } = require("child_process"); const ethers = require("ethers"); +const { FORKED_XDAI_CHAINID } = require("./helpers/constants"); + const existingCompileComplete = config.onCompileComplete; let chainId; @@ -11,9 +13,9 @@ let chainId; // TODO: Actually query nodes, don't hard-code here, or work out how to get environment // variables in package.json to work here as I want. if (JSON.parse(process.env.TRUFFLE_FOREIGN)){ - chainId = 265669101; + chainId = FORKED_XDAI_CHAINID + 1; } else { - chainId = 265669100; + chainId = FORKED_XDAI_CHAINID; } config.providerOptions.network_id = chainId; diff --git a/contracts/colony/Colony.sol b/contracts/colony/Colony.sol index 284062da4c..4f7bfdba49 100755 --- a/contracts/colony/Colony.sol +++ b/contracts/colony/Colony.sol @@ -215,11 +215,11 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP IColonyNetwork(colonyNetworkAddress).addColonyVersion(_version, _resolver); } - function setBridgeData(address bridgeAddress, bytes memory updateLogBefore, bytes memory updateLogAfter, uint256 gas, uint256 chainId, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) external + function setBridgeData(address bridgeAddress, uint256 chainId, uint256 gas, bytes memory updateLogBefore, bytes memory updateLogAfter, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) external stoppable auth { - IColonyNetwork(colonyNetworkAddress).setBridgeData(bridgeAddress, updateLogBefore, updateLogAfter, gas, chainId, skillCreationBefore, skillCreationAfter, setReputationRootHashBefore, setReputationRootHashAfter); + IColonyNetwork(colonyNetworkAddress).setBridgeData(bridgeAddress, chainId, gas, updateLogBefore, updateLogAfter, skillCreationBefore, skillCreationAfter, setReputationRootHashBefore, setReputationRootHashAfter); } function addExtensionToNetwork(bytes32 _extensionId, address _resolver) @@ -323,7 +323,7 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP ColonyAuthority colonyAuthority = ColonyAuthority(address(authority)); bytes4 sig; - sig = bytes4(keccak256("setBridgeData(address,bytes,bytes,uint256,uint256,bytes,bytes,bytes,bytes)")); + sig = bytes4(keccak256("setBridgeData(address,uint256,uint256,bytes,bytes,bytes,bytes,bytes,bytes)")); colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true); } diff --git a/contracts/colony/ColonyAuthority.sol b/contracts/colony/ColonyAuthority.sol index 47c18db1b5..1b43ee6339 100644 --- a/contracts/colony/ColonyAuthority.sol +++ b/contracts/colony/ColonyAuthority.sol @@ -131,7 +131,7 @@ contract ColonyAuthority is CommonAuthority { addRoleCapability(ARBITRATION_ROLE, "setExpenditurePayout(uint256,uint256,uint256,uint256,address,uint256)"); // Added in colony vxxx - addRoleCapability(ROOT_ROLE, "setBridgeData(address,bytes,bytes,uint256,uint256,bytes,bytes,bytes,bytes)"); + addRoleCapability(ROOT_ROLE, "setBridgeData(address,uint256,uint256,bytes,bytes,bytes,bytes,bytes,bytes)"); } function addRoleCapability(uint8 role, bytes memory sig) private { diff --git a/contracts/colony/IMetaColony.sol b/contracts/colony/IMetaColony.sol index 0446f7526f..d97e669224 100644 --- a/contracts/colony/IMetaColony.sol +++ b/contracts/colony/IMetaColony.sol @@ -67,13 +67,13 @@ interface IMetaColony is IColony { /// @notice Called to set the details about bridge _bridgeAddress /// @param _bridgeAddress The address of the bridge + /// @param chainId The chainId of the corresponding network + /// @param gas How much gas to use for a bridged transaction /// @param updateLogBefore The tx data before the dynamic part of the tx to bridge to the update log /// @param updateLogAfter The tx data after the dynamic part of the tx to bridge to the update log - /// @param gas How much gas to use for a bridged transaction - /// @param chainId The chainId of the corresponding network /// @param skillCreationBefore The tx data before the dynamic part of the tx to brdige skill creation /// @param skillCreationAfter The tx data after the dynamic part of the tx to brdige skill creation /// @param setReputationRootHashBefore The tx data before the dynamic part of the tx to bridge a new reputation root hash /// @param setReputationRootHashAfter The tx data after the dynamic part of the tx to bridge a new reputation root hash - function setBridgeData(address _bridgeAddress, bytes memory updateLogBefore, bytes memory updateLogAfter, uint256 gas, uint256 chainId, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) external; + function setBridgeData(address _bridgeAddress, uint256 chainId, uint256 gas, bytes memory updateLogBefore, bytes memory updateLogAfter, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) external; } diff --git a/contracts/colonyNetwork/ColonyNetwork.sol b/contracts/colonyNetwork/ColonyNetwork.sol index 25adfec44f..0a70fd85b4 100644 --- a/contracts/colonyNetwork/ColonyNetwork.sol +++ b/contracts/colonyNetwork/ColonyNetwork.sol @@ -102,20 +102,20 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall emit ColonyVersionAdded(_version, _resolver); } - function setBridgeData(address bridgeAddress, bytes memory updateLogBefore, bytes memory updateLogAfter, uint256 gas, uint256 chainId, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) public + function setBridgeData(address bridgeAddress, uint256 chainId, uint256 gas, bytes memory updateLogBefore, bytes memory updateLogAfter, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) public always calledByMetaColony { if (!isMiningChain()) { - miningBridgeAddress = bridgeAddress; require(isMiningChainId(chainId), "colony-network-can-only-set-mining-chain-bridge"); + miningBridgeAddress = bridgeAddress; } bridgeData[bridgeAddress] = Bridge(updateLogBefore, updateLogAfter, gas, chainId, skillCreationBefore, skillCreationAfter, setReputationRootHashBefore, setReputationRootHashAfter); if (networkSkillCounts[chainId] == 0) { // Initialise the skill count to match the foreign chain networkSkillCounts[chainId] = chainId << 128; } - // emit BridgeDataSet + emit BridgeDataSet(bridgeAddress); } function getBridgeData(address bridgeAddress) public view returns (Bridge memory) { @@ -238,15 +238,15 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall function addSkillFromBridge(uint256 _parentSkillId, uint256 _skillId) public always onlyMiningChain() { // Require is a known bridge - Bridge storage bridge = bridgeData[msgSender()]; - require(bridge.chainId != 0, "colony-network-not-known-bridge"); + uint256 bridgeChainId = bridgeData[msgSender()].chainId; + require(bridgeChainId != 0, "colony-network-not-known-bridge"); // Check skill count - if not next, then store for later. - if (networkSkillCounts[bridge.chainId] + 1 == _skillId){ + if (networkSkillCounts[bridgeChainId] + 1 == _skillId){ addSkillToChainTree(_parentSkillId, _skillId); - networkSkillCounts[bridge.chainId] += 1; - } else if (networkSkillCounts[bridge.chainId] < _skillId){ - pendingSkillAdditions[bridge.chainId][_skillId] = _parentSkillId; + networkSkillCounts[bridgeChainId] += 1; + } else if (networkSkillCounts[bridgeChainId] < _skillId){ + pendingSkillAdditions[bridgeChainId][_skillId] = _parentSkillId; // TODO: Event? } } @@ -260,20 +260,20 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall } function addBridgedPendingSkill(address _bridgeAddress, uint256 _skillId) public always onlyMiningChain() { - Bridge storage bridge = bridgeData[_bridgeAddress]; - require(bridge.chainId != 0, "colony-network-not-known-bridge"); + uint256 bridgeChainId = bridgeData[_bridgeAddress].chainId; + require(bridgeChainId != 0, "colony-network-not-known-bridge"); // Require that specified skill is next // Note this also implicitly checks that the chainId prefix of the skill is correct - require(networkSkillCounts[bridge.chainId] + 1 == _skillId, "colony-network-not-next-bridged-skill"); + require(networkSkillCounts[bridgeChainId] + 1 == _skillId, "colony-network-not-next-bridged-skill"); - uint256 parentSkillId = pendingSkillAdditions[bridge.chainId][_skillId]; + uint256 parentSkillId = pendingSkillAdditions[bridgeChainId][_skillId]; require(parentSkillId != 0, "colony-network-no-such-bridged-skill"); addSkillToChainTree(parentSkillId, _skillId); - networkSkillCounts[bridge.chainId] += 1; + networkSkillCounts[bridgeChainId] += 1; // Delete the pending addition - delete pendingSkillAdditions[bridge.chainId][_skillId]; + delete pendingSkillAdditions[bridgeChainId][_skillId]; } function getParentSkillId(uint _skillId, uint _parentSkillIndex) public view returns (uint256) { @@ -314,19 +314,21 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall return skillCount; } - function appendReputationUpdateLogFromBridge(address _colony, address _user, int _amount, uint _skillId, uint256 _updateNumber) public onlyMiningChain stoppable + function appendReputationUpdateLogFromBridge(address _colony, address _user, int256 _amount, uint256 _skillId, uint256 _updateNumber) public onlyMiningChain stoppable { // Require is a known bridge - require(bridgeData[msgSender()].chainId != 0, "colony-network-not-known-bridge"); + uint256 bridgeChainId = bridgeData[msgSender()].chainId; + + require(bridgeChainId != 0, "colony-network-not-known-bridge"); - require(bridgeData[msgSender()].chainId == _skillId >> 128, "colony-network-invalid-skill-id-for-bridge"); + require(bridgeChainId == _skillId >> 128, "colony-network-invalid-skill-id-for-bridge"); // if next expected update, add to log if ( - reputationUpdateCount[bridgeData[msgSender()].chainId][_colony] + 1 == _updateNumber && // It's the next reputation update for this colony + reputationUpdateCount[bridgeChainId][_colony] + 1 == _updateNumber && // It's the next reputation update for this colony networkSkillCounts[_skillId >> 128] >= _skillId // Skill has been bridged ){ - reputationUpdateCount[bridgeData[msgSender()].chainId][_colony] += 1; + reputationUpdateCount[bridgeChainId][_colony] += 1; uint128 nParents = skills[_skillId].nParents; // We only update child skill reputation if the update is negative, otherwise just set nChildren to 0 to save gas uint128 nChildren = _amount < 0 ? skills[_skillId].nChildren : 0; @@ -342,7 +344,7 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall } else { // Not next update, store for later - pendingReputationUpdates[bridgeData[msgSender()].chainId][_colony][_updateNumber] = PendingReputationUpdate(_colony, _user, _amount, _skillId, block.timestamp); + pendingReputationUpdates[bridgeChainId][_colony][_updateNumber] = PendingReputationUpdate(_user, _amount, _skillId, _colony, block.timestamp); } } @@ -370,13 +372,13 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall } function addBridgedReputationUpdate(uint256 _chainId, address _colony) public stoppable onlyMiningChain { - uint256 nextUpdateNumber = reputationUpdateCount[_chainId][_colony] + 1; + uint256 mostRecentUpdateNumber = reputationUpdateCount[_chainId][_colony]; + PendingReputationUpdate storage pendingUpdate = pendingReputationUpdates[_chainId][_colony][mostRecentUpdateNumber + 1]; + // Bridged update must exist - require(pendingReputationUpdates[_chainId][_colony][nextUpdateNumber].colony != address(0x00), "colony-network-next-update-does-not-exist"); + require(pendingUpdate.colony != address(0x00), "colony-network-next-update-does-not-exist"); // It should be the next one - assert(pendingReputationUpdates[_chainId][_colony][nextUpdateNumber - 1].colony == address(0x00)); - - PendingReputationUpdate storage pendingUpdate = pendingReputationUpdates[_chainId][_colony][nextUpdateNumber]; + assert(pendingReputationUpdates[_chainId][_colony][mostRecentUpdateNumber].colony == address(0x00)); // Skill creation must have been bridged require(networkSkillCounts[pendingUpdate.skillId >> 128] >= pendingUpdate.skillId, "colony-network-invalid-skill-id"); @@ -387,10 +389,10 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall int256 updateAmount = decayReputation(pendingUpdate.amount, pendingUpdate.timestamp); - reputationUpdateCount[_chainId][_colony] +=1; + reputationUpdateCount[_chainId][_colony] += 1; address user = pendingUpdate.user; uint256 skillId = pendingUpdate.skillId; - delete pendingReputationUpdates[_chainId][_colony][nextUpdateNumber]; + delete pendingReputationUpdates[_chainId][_colony][mostRecentUpdateNumber + 1]; IReputationMiningCycle(inactiveReputationMiningCycle).appendReputationUpdateLog( user, @@ -453,7 +455,7 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall (bool success, ) = miningBridgeAddress.call(payload); if (!success || !isContract(miningBridgeAddress)) { // Store to resend later - pendingReputationUpdates[getChainId()][msgSender()][reputationUpdateCount[getChainId()][msgSender()]] = PendingReputationUpdate(msgSender(), _user, _amount, _skillId, block.timestamp); + pendingReputationUpdates[getChainId()][msgSender()][reputationUpdateCount[getChainId()][msgSender()]] = PendingReputationUpdate(_user, _amount, _skillId, msgSender(), block.timestamp); } // TODO: How do we emit events here? } diff --git a/contracts/colonyNetwork/ColonyNetworkDataTypes.sol b/contracts/colonyNetwork/ColonyNetworkDataTypes.sol index b47c8c4e9d..828832a7de 100755 --- a/contracts/colonyNetwork/ColonyNetworkDataTypes.sol +++ b/contracts/colonyNetwork/ColonyNetworkDataTypes.sol @@ -145,6 +145,10 @@ interface ColonyNetworkDataTypes { /// @param tokenAuthorityAddress The address of the token authority deployed event TokenAuthorityDeployed(address tokenAuthorityAddress); + /// @notice Event logged when the colony network has data about a bridge contract set. + /// @param bridgeAddress The address of the bridge contract that will be interacted with + event BridgeDataSet(address bridgeAddress); + struct Skill { // total number of parent skills uint128 nParents; @@ -191,10 +195,10 @@ interface ColonyNetworkDataTypes { } struct PendingReputationUpdate { - address colony; address user; int256 amount; uint skillId; + address colony; uint256 timestamp; } } diff --git a/contracts/colonyNetwork/ColonyNetworkMining.sol b/contracts/colonyNetwork/ColonyNetworkMining.sol index 9347abc88e..77d71bfab1 100644 --- a/contracts/colonyNetwork/ColonyNetworkMining.sol +++ b/contracts/colonyNetwork/ColonyNetworkMining.sol @@ -93,14 +93,14 @@ contract ColonyNetworkMining is ColonyNetworkStorage { emit ReputationRootHashSet(newHash, newNLeaves, newAddressArray(), 0); } - function bridgeCurrentRootHash(address bridgeAddress) onlyMiningChain stoppable public { - require(bridgeData[bridgeAddress].chainId != 0, "colony-network-not-known-bridge"); + function bridgeCurrentRootHash(address _bridgeAddress) onlyMiningChain stoppable public { + require(bridgeData[_bridgeAddress].chainId != 0, "colony-network-not-known-bridge"); bytes memory payload = abi.encodePacked( - bridgeData[bridgeAddress].setReputationRootHashBefore, + bridgeData[_bridgeAddress].setReputationRootHashBefore, abi.encodeWithSignature("setReputationRootHashFromBridge(bytes32,uint256)", reputationRootHash, reputationRootHashNLeaves), - bridgeData[bridgeAddress].setReputationRootHashAfter + bridgeData[_bridgeAddress].setReputationRootHashAfter ); - (bool success, ) = bridgeAddress.call(payload); + (bool success, ) = _bridgeAddress.call(payload); // TODO: Do we require success here? require(success, "colony-mining-bridge-call-failed"); } diff --git a/contracts/colonyNetwork/ColonyNetworkStorage.sol b/contracts/colonyNetwork/ColonyNetworkStorage.sol index 5590e71cda..1a76924d2d 100644 --- a/contracts/colonyNetwork/ColonyNetworkStorage.sol +++ b/contracts/colonyNetwork/ColonyNetworkStorage.sol @@ -116,10 +116,10 @@ contract ColonyNetworkStorage is ColonyNetworkDataTypes, DSMath, CommonStorage, // networkId -> skillCount -> parentSkillId mapping(uint256 => mapping(uint256 => uint256)) pendingSkillAdditions; // Storage slot 46 - // networkId -> colonyAddress -> updateCount -> update - mapping(uint256 => mapping( address => mapping(uint256 => PendingReputationUpdate))) pendingReputationUpdates; // Storage slot 47 // networkID -> colonyAddress -> updateCount mapping(uint256 => mapping( address => uint256)) reputationUpdateCount; // Storage slot 48 + // networkId -> colonyAddress -> updateCount -> update + mapping(uint256 => mapping( address => mapping(uint256 => PendingReputationUpdate))) pendingReputationUpdates; // Storage slot 47 modifier calledByColony() { require(_isColony[msgSender()], "colony-caller-must-be-colony"); diff --git a/contracts/colonyNetwork/IColonyNetwork.sol b/contracts/colonyNetwork/IColonyNetwork.sol index a453b3e1f6..cad350a85d 100644 --- a/contracts/colonyNetwork/IColonyNetwork.sol +++ b/contracts/colonyNetwork/IColonyNetwork.sol @@ -465,15 +465,15 @@ interface IColonyNetwork is ColonyNetworkDataTypes, IRecovery, IBasicMetaTransac /// @notice Called to set the details about bridge _bridgeAddress /// @param _bridgeAddress The address of the bridge + /// @param chainId The chainId of the corresponding network + /// @param gas How much gas to use for a bridged transaction /// @param updateLogBefore The tx data before the dynamic part of the tx to bridge to the update log /// @param updateLogAfter The tx data after the dynamic part of the tx to bridge to the update log - /// @param gas How much gas to use for a bridged transaction - /// @param chainId The chainId of the corresponding network /// @param skillCreationBefore The tx data before the dynamic part of the tx to brdige skill creation /// @param skillCreationAfter The tx data after the dynamic part of the tx to brdige skill creation /// @param setReputationRootHashBefore The tx data before the dynamic part of the tx to bridge a new reputation root hash /// @param setReputationRootHashAfter The tx data after the dynamic part of the tx to bridge a new reputation root hash - function setBridgeData(address _bridgeAddress, bytes memory updateLogBefore, bytes memory updateLogAfter, uint256 gas, uint256 chainId, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) external; + function setBridgeData(address _bridgeAddress, uint256 chainId, uint256 gas, bytes memory updateLogBefore, bytes memory updateLogAfter, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter) external; /// @notice Called to get the details about known bridge _bridgeAddress /// @param _bridgeAddress The address of the bridge diff --git a/contracts/common/MultiChain.sol b/contracts/common/MultiChain.sol index cfe7da288a..23a97dfc50 100644 --- a/contracts/common/MultiChain.sol +++ b/contracts/common/MultiChain.sol @@ -51,7 +51,7 @@ contract MultiChain { } function isMiningChainId(uint256 chainId) internal view returns (bool) { - return (chainId == 100 || chainId == 265669100); + return (chainId == MINING_CHAIN_ID || chainId == 265669100); } uint256 constant MINING_CHAIN_ID = 100; diff --git a/contracts/testHelpers/BridgeMock.sol b/contracts/testHelpers/BridgeMock.sol index a119d368f5..1b579d9188 100644 --- a/contracts/testHelpers/BridgeMock.sol +++ b/contracts/testHelpers/BridgeMock.sol @@ -41,16 +41,6 @@ contract BridgeMock { } } - // bool success; - // assembly { - // // call contract at address a with input mem[in…(in+insize)) - // // providing g gas and v wei and output area mem[out…(out+outsize)) - // // returning 0 on error (eg. out of gas) and 1 on success - - // // call(g, a, v, in, insize, out, outsize) - // success := call(_gasLimit, _target, 0, add(_data, 0x20), mload(_data), 0, 0) - // } - emit RelayedMessage(_sender, msg.sender, _messageId, success); } diff --git a/docs/interfaces/icolonynetwork.md b/docs/interfaces/icolonynetwork.md index 8689512f11..d0267368bf 100644 --- a/docs/interfaces/icolonynetwork.md +++ b/docs/interfaces/icolonynetwork.md @@ -1061,7 +1061,7 @@ Used to track that a user is eligible to claim a reward |_amount|uint256|The amount of CLNY to be awarded -### ▸ `setBridgeData(address _bridgeAddress, bytes memory updateLogBefore, bytes memory updateLogAfter, uint256 gas, uint256 chainId, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter)` +### ▸ `setBridgeData(address _bridgeAddress, uint256 chainId, uint256 gas, bytes memory updateLogBefore, bytes memory updateLogAfter, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter)` Called to set the details about bridge _bridgeAddress @@ -1071,10 +1071,10 @@ Called to set the details about bridge _bridgeAddress |Name|Type|Description| |---|---|---| |_bridgeAddress|address|The address of the bridge +|chainId|uint256|The chainId of the corresponding network +|gas|uint256|How much gas to use for a bridged transaction |updateLogBefore|bytes|The tx data before the dynamic part of the tx to bridge to the update log |updateLogAfter|bytes|The tx data after the dynamic part of the tx to bridge to the update log -|gas|uint256|How much gas to use for a bridged transaction -|chainId|uint256|The chainId of the corresponding network |skillCreationBefore|bytes|The tx data before the dynamic part of the tx to brdige skill creation |skillCreationAfter|bytes|The tx data after the dynamic part of the tx to brdige skill creation |setReputationRootHashBefore|bytes|The tx data before the dynamic part of the tx to bridge a new reputation root hash diff --git a/docs/interfaces/imetacolony.md b/docs/interfaces/imetacolony.md index 70584e0de4..a907c2124e 100644 --- a/docs/interfaces/imetacolony.md +++ b/docs/interfaces/imetacolony.md @@ -73,7 +73,7 @@ Mints CLNY in the Meta Colony and transfers them to the colony network. Only all |_wad|uint256|Amount to mint and transfer to the colony network -### ▸ `setBridgeData(address _bridgeAddress, bytes memory updateLogBefore, bytes memory updateLogAfter, uint256 gas, uint256 chainId, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter)` +### ▸ `setBridgeData(address _bridgeAddress, uint256 chainId, uint256 gas, bytes memory updateLogBefore, bytes memory updateLogAfter, bytes memory skillCreationBefore, bytes memory skillCreationAfter, bytes memory setReputationRootHashBefore, bytes memory setReputationRootHashAfter)` Called to set the details about bridge _bridgeAddress @@ -83,10 +83,10 @@ Called to set the details about bridge _bridgeAddress |Name|Type|Description| |---|---|---| |_bridgeAddress|address|The address of the bridge +|chainId|uint256|The chainId of the corresponding network +|gas|uint256|How much gas to use for a bridged transaction |updateLogBefore|bytes|The tx data before the dynamic part of the tx to bridge to the update log |updateLogAfter|bytes|The tx data after the dynamic part of the tx to bridge to the update log -|gas|uint256|How much gas to use for a bridged transaction -|chainId|uint256|The chainId of the corresponding network |skillCreationBefore|bytes|The tx data before the dynamic part of the tx to brdige skill creation |skillCreationAfter|bytes|The tx data after the dynamic part of the tx to brdige skill creation |setReputationRootHashBefore|bytes|The tx data before the dynamic part of the tx to bridge a new reputation root hash diff --git a/helpers/constants.js b/helpers/constants.js index 3c080f341f..be347ff3be 100644 --- a/helpers/constants.js +++ b/helpers/constants.js @@ -73,6 +73,11 @@ const DECAY_RATE = { const GLOBAL_SKILL_ID = new BN("4"); // Not a root global skill ID or anything, just the first global skill's ID +const XDAI_CHAINID = 100; +const FORKED_XDAI_CHAINID = 265669100; +const MAINNET_CHAINID = 100; +const FORKED_MAINNET_CHAINID = 265669100; + module.exports = { UINT256_MAX, UINT128_MAX, @@ -122,4 +127,8 @@ module.exports = { IPFS_HASH, HASHZERO, ADDRESS_ZERO, + XDAI_CHAINID, + FORKED_XDAI_CHAINID, + MAINNET_CHAINID, + FORKED_MAINNET_CHAINID, }; diff --git a/helpers/test-helper.js b/helpers/test-helper.js index e8993b8579..6156265e53 100644 --- a/helpers/test-helper.js +++ b/helpers/test-helper.js @@ -6,7 +6,17 @@ const BN = require("bn.js"); const { ethers } = require("ethers"); const { BigNumber } = require("bignumber.js"); -const { UINT256_MAX, MIN_STAKE, MINING_CYCLE_DURATION, DEFAULT_STAKE, CHALLENGE_RESPONSE_WINDOW_DURATION } = require("./constants"); +const { + UINT256_MAX, + MIN_STAKE, + MINING_CYCLE_DURATION, + DEFAULT_STAKE, + CHALLENGE_RESPONSE_WINDOW_DURATION, + XDAI_CHAINID, + FORKED_XDAI_CHAINID, + MAINNET_CHAINID, + FORKED_MAINNET_CHAINID, +} = require("./constants"); const IColony = artifacts.require("IColony"); const IMetaColony = artifacts.require("IMetaColony"); @@ -1147,12 +1157,12 @@ exports.sleep = function sleep(ms) { exports.isMainnet = async function isMainnet() { const chainId = await exports.web3GetChainId(); - return chainId === 1 || chainId === 2656691; + return chainId === MAINNET_CHAINID || chainId === FORKED_MAINNET_CHAINID; }; exports.isXdai = async function isXdai() { const chainId = await exports.web3GetChainId(); - return chainId === 100 || chainId === 265669100; + return chainId === XDAI_CHAINID || chainId === FORKED_XDAI_CHAINID; }; class TestAdapter { diff --git a/migrations/6_setup_mining_cycle_resolver.js b/migrations/6_setup_mining_cycle_resolver.js index c345d9a75a..9ab7a64867 100644 --- a/migrations/6_setup_mining_cycle_resolver.js +++ b/migrations/6_setup_mining_cycle_resolver.js @@ -1,6 +1,7 @@ /* globals artifacts */ const { setupReputationMiningCycleResolver } = require("../helpers/upgradable-contracts"); +const { XDAI_CHAINID, FORKED_XDAI_CHAINID } = require("../helpers/constants"); const IColonyNetwork = artifacts.require("./IColonyNetwork"); const ReputationMiningCycle = artifacts.require("./ReputationMiningCycle"); @@ -17,7 +18,7 @@ module.exports = async function (deployer) { const multichain = await MultiChain.new(); const chainId = await multichain.getChainId(); - if (chainId.toString() !== "265669100" && chainId.toString() !== "100") { + if (chainId.toNumber() !== FORKED_XDAI_CHAINID && chainId.toNumber() !== XDAI_CHAINID) { console.log("Not mining chain, skipping setting up mining cycle resolver"); return; } diff --git a/test/cross-chain/cross-chain.js b/test/cross-chain/cross-chain.js index b367d37539..9e2dfd3667 100644 --- a/test/cross-chain/cross-chain.js +++ b/test/cross-chain/cross-chain.js @@ -53,6 +53,8 @@ contract("Cross-chain", (accounts) => { const TRUFFLE_PORT = process.env.SOLIDITY_COVERAGE ? 8555 : 8545; const OTHER_RPC_PORT = 8546; + const MINER_ADDRESS = accounts[5]; + const HOME_PORT = process.env.TRUFFLE_FOREIGN === "true" ? OTHER_RPC_PORT : TRUFFLE_PORT; const FOREIGN_PORT = process.env.TRUFFLE_FOREIGN === "true" ? TRUFFLE_PORT : OTHER_RPC_PORT; @@ -134,40 +136,64 @@ contract("Cross-chain", (accounts) => { const homeMCAddress = await homeColonyNetwork.getMetaColony(); homeMetacolony = await new ethers.Contract(homeMCAddress, IMetaColony.abi, ethersHomeSigner); + // The code here demonstrates how to generate the bridge data for a bridge. We work out the transaction (with dummy data), and then + // the transaction that would call that on the AMB, before snipping out the AMB call. The non-dummy data is worked out on-chain before + // being sandwiched by the before and after bytes. + const appendReputationUpdateLogFromBridgeTx = homeColonyNetwork.interface.encodeFunctionData("appendReputationUpdateLogFromBridge", [ + "0x1111111111111111111111111111111111111111", + "0x2222222222222222222222222222222222222222", + 0x666666, + 0x88888888, + 0x99999999, + ]); + const appendReputationUpdateLogFromBridgeTxDataToBeSentToAMB = homeBridge.interface.encodeFunctionData("requireToPassMessage", [ + homeColonyNetwork.address, + appendReputationUpdateLogFromBridgeTx, + 1000000, + ]); + + const addSkillFromBridgeTx = homeColonyNetwork.interface.encodeFunctionData("addSkillFromBridge", [0x666666, 0x88888888]); + const addSkillFromBridgeTxDataToBeSentToAMB = homeBridge.interface.encodeFunctionData("requireToPassMessage", [ + homeColonyNetwork.address, + addSkillFromBridgeTx, + 1000000, + ]); + let tx = await foreignMetacolony.setBridgeData( foreignBridge.address, // bridge address - `0xdc8601b3000000000000000000000000${homeColonyNetwork.address.slice( - 2 - // eslint-disable-next-line max-len - )}000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000a4`, // log before - "0x00000000000000000000000000000000000000000000000000000000", // log after - 1000000, // gas 100, // chainid - `0xdc8601b3000000000000000000000000${homeColonyNetwork.address.slice( - 2 - // )}000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000000000000044`, // skill before - // eslint-disable-next-line max-len - )}000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000001e84800000000000000000000000000000000000000000000000000000000000000044`, // skill before //eslint-disable-line max-len - "0x00000000000000000000000000000000000000000000000000000000", // skill after + 1000000, // gas + appendReputationUpdateLogFromBridgeTxDataToBeSentToAMB.slice(0, 266), // log before + `0x${appendReputationUpdateLogFromBridgeTxDataToBeSentToAMB.slice(-56)}`, // log after + addSkillFromBridgeTxDataToBeSentToAMB.slice(0, 266), // skill before + `0x${addSkillFromBridgeTxDataToBeSentToAMB.slice(-56)}`, // skill after "0x", // root hash before "0x" // root hash after ); await tx.wait(); + const setReputationRootHashFromBridgeTx = homeColonyNetwork.interface.encodeFunctionData("setReputationRootHashFromBridge", [ + "0xb8b89e7cf61d1d39d09e98c0ccbb489561e5e1173445a6b34e469f362ebdb221", + "0xb8b89e7cf61d1d39d09e98c0ccbb489561e5e1173445a6b34e469f362ebdb221", + ]); + const setReputationRootHashFromBridgeTxDataToBeSentToAMB = homeBridge.interface.encodeFunctionData("requireToPassMessage", [ + foreignColonyNetwork.address, + setReputationRootHashFromBridgeTx, + 1000000, + ]); + console.log(setReputationRootHashFromBridgeTxDataToBeSentToAMB); + tx = await homeMetacolony.setBridgeData( homeBridge.address, // bridge address + foreignChainId, // chainid + 1000000, // gas "0x", // log before "0x", // log after - 1000000, // gas - foreignChainId, // chainid `0x`, // skill before "0x", // skill after - `0xdc8601b3000000000000000000000000${foreignColonyNetwork.address.slice( - 2 - // eslint-disable-next-line max-len - )}000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000000000000044`, - "0x00000000000000000000000000000000000000000000000000000000" // root hash after + setReputationRootHashFromBridgeTxDataToBeSentToAMB.slice(0, 266), // root hash before + `0x${setReputationRootHashFromBridgeTxDataToBeSentToAMB.slice(-56)}` // root hash after ); await tx.wait(); @@ -182,21 +208,18 @@ contract("Cross-chain", (accounts) => { await p; } - console.log("adsf1"); // Set up mining client client = new ReputationMinerTestWrapper({ loader: contractLoader, - minerAddress: accounts[5], + minerAddress: MINER_ADDRESS, realProviderPort: HOME_PORT, useJsTree: true, }); - console.log("adsf2"); await client.initialise(homeColonyNetwork.address); web3HomeProvider = new web3.eth.providers.HttpProvider(ethersHomeSigner.provider.connection.url); web3ForeignProvider = new web3.eth.providers.HttpProvider(ethersForeignSigner.provider.connection.url); - console.log("adsf3"); await forwardTime(MINING_CYCLE_DURATION + CHALLENGE_RESPONSE_WINDOW_DURATION, undefined, web3HomeProvider); await client.addLogContentsToReputationTree(); await client.submitRootHash(); @@ -206,19 +229,6 @@ contract("Cross-chain", (accounts) => { await client.addLogContentsToReputationTree(); await client.submitRootHash(); await client.confirmNewHash(); - - console.log("asdf4"); - // Bridge over pending reputation updates that have been emitted on the foreign chain - // const reputationLogCounter = await foreignColonyNetwork.getBridgedReputationUpdateCount(foreignChainId, foreignColonyNetwork.address); - - // console.log('asdf5') - // for (let i = 1; i <= reputationLogCounter; i+=1) { - // const p = getPromiseForNextBridgedTransaction(); - // tx = await foreignColonyNetwork.bridgePendingReputationUpdate(i); - // res = await tx.wait(); - // console.log(res); - // await p; - // } }); async function setupColony(colonyNetworkEthers) { @@ -292,12 +302,12 @@ contract("Cross-chain", (accounts) => { }); it("setBridgeData can only be called by the metacolony", async () => { - const tx = await foreignColonyNetwork.setBridgeData(ADDRESS_ZERO, "0x00", "0x00", 0, 1, "0x00", "0x00", "0x00", "0x00", { gasLimit: 1000000 }); + const tx = await foreignColonyNetwork.setBridgeData(ADDRESS_ZERO, 1, 0, "0x00", "0x00", "0x00", "0x00", "0x00", "0x00", { gasLimit: 1000000 }); await checkErrorRevertEthers(tx.wait(), "colony-caller-must-be-meta-colony"); }); it("setBridgeData can only set the mining chain bridge on a not-mining chain", async () => { - const tx = await foreignMetacolony.setBridgeData(ADDRESS_ZERO, "0x00", "0x00", 0, 1, "0x00", "0x00", "0x00", "0x00", { gasLimit: 1000000 }); + const tx = await foreignMetacolony.setBridgeData(ADDRESS_ZERO, 1, 0, "0x00", "0x00", "0x00", "0x00", "0x00", "0x00", { gasLimit: 1000000 }); await checkErrorRevertEthers(tx.wait(), "colony-network-can-only-set-mining-chain-bridge"); }); @@ -305,10 +315,10 @@ contract("Cross-chain", (accounts) => { const countBefore = await homeColonyNetwork.getBridgedSkillCounts(foreignChainId); const tx = await homeMetacolony.setBridgeData( homeBridge.address, // bridge address + foreignChainId, // chainid + 1000000, // gas "0x", // log before "0x", // log after - 1000000, // gas - foreignChainId, // chainid `0x`, // skill before "0x", // skill after `0xdc8601b3000000000000000000000000${foreignColonyNetwork.address.slice( @@ -376,11 +386,6 @@ contract("Cross-chain", (accounts) => { describe("when adding skills on another chain", async () => { it("can create a skill on another chain and it's reflected on the home chain", async () => { - // const t = homeColonyNetwork.interface.encodeFunctionData("addSkillFromBridge", [0x666666, 0x88888888]); - // console.log(t); - // const txDataToBeSentToAMB = homeBridge.interface.encodeFunctionData("requireToPassMessage", [homeColonyNetwork.address, t, 1000000]); - // console.log(txDataToBeSentToAMB); - // See skills on home chain const beforeCount = await homeColonyNetwork.getBridgedSkillCounts("0x0fd5c9ed"); @@ -578,27 +583,6 @@ contract("Cross-chain", (accounts) => { describe("while earning reputation on another chain", async () => { it("reputation awards are ultimately reflected", async () => { - // const t = homeColonyNetwork.interface.encodeFunctionData("appendReputationUpdateLogFromBridge", [ - // "0x1471c2dc50d9155d80E4C88187806Df6B1a2e649", - // "0x1471c2dc50d9155d80E4C88187806Df6B1a2e649", - // 0x666666, - // 0x88888888, - // 0x99999999, - // ]); - // console.log(t); - // const txDataToBeSentToAMB = homeBridge.interface.encodeFunctionData("requireToPassMessage", [homeColonyNetwork.address, t, 1000000]); - // console.log(txDataToBeSentToAMB); - // process.exit(1) - - // const t = homeColonyNetwork.interface.encodeFunctionData("bridgeSetReputationRootHash", [ - // "0xb8b89e7cf61d1d39d09e98c0ccbb489561e5e1173445a6b34e469f362ebdb221", - // "0xb8b89e7cf61d1d39d09e98c0ccbb489561e5e1173445a6b34e469f362ebdb221" - // ]); - // console.log(t); - // const txDataToBeSentToAMB = homeBridge.interface.encodeFunctionData("requireToPassMessage", [foreignColonyNetwork.address, t, 1000000]); - // console.log(txDataToBeSentToAMB); - - // process.exit(1) let p = getPromiseForNextBridgedTransaction(); // Emit reputation await foreignColony.emitDomainReputationReward(1, accounts[0], "0x1337");