diff --git a/.github/workflows/sast.yaml b/.github/workflows/sast.yaml new file mode 100644 index 000000000..8d50fbf14 --- /dev/null +++ b/.github/workflows/sast.yaml @@ -0,0 +1,40 @@ +name: Static analysis + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + slither: + name: Slither check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Run Slither + uses: crytic/slither-action@v0.3.0 + with: + fail-on: low + + solhint: + name: Solhint check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup Node 16 + uses: actions/setup-node@v3 + with: + node-version: '16.x' + cache: 'npm' + - name: Install Node dependencies + run: npm i --unsafe-perm + - name: Install solidity plugin + run: npm i --unsafe-perm prettier prettier-plugin-solidity + - name: Prettier check + run: npx prettier --check 'src/**/*.sol' 'test/*.sol' + - name: Solhint check + run: npx solhint 'src/**/*.sol' diff --git a/.github/workflows/blank.yml b/.github/workflows/test.yml similarity index 70% rename from .github/workflows/blank.yml rename to .github/workflows/test.yml index 960789993..86bb581cd 100644 --- a/.github/workflows/blank.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Slither Analysis +name: Tests on: push: @@ -7,7 +7,7 @@ on: branches: [ main ] jobs: - analyze: + tests: runs-on: ubuntu-latest permissions: contents: read @@ -24,9 +24,3 @@ jobs: - name: Run tests run: forge test -vvv - - - name: Run Slither - uses: crytic/slither-action@dev-git-safe-workspace - with: - fail-on: low - target: 'src/' diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..0fadc34fc --- /dev/null +++ b/.prettierrc @@ -0,0 +1,21 @@ +{ + semi: false, + singleQuote: true, + printWidth: 80, + endOfLine: 'auto', + tabWidth: 4, + trailingComma: 'all', + overrides: [ + { + files: '*.sol', + options: { + parser: 'solidity-parse', + printWidth: 120, + tabWidth: 4, + useTabs: false, + singleQuote: false, + bracketSpacing: false, + }, + }, + ], +} \ No newline at end of file diff --git a/.solhint.json b/.solhint.json index 48ada8d5c..a211db916 100644 --- a/.solhint.json +++ b/.solhint.json @@ -3,7 +3,24 @@ "rules": { "compiler-version": ["error", "0.8.18"], "func-visibility": ["warn", { "ignoreConstructors": true }], - "prettier/prettier": "error", - "no-global-import": "off" + "no-global-import": "off", + "no-unused-vars": "error", + "const-name-snakecase": "error", + "contract-name-camelcase": "error", + "event-name-camelcase": "error", + "func-name-mixedcase": "error", + "func-param-name-mixedcase": "error", + "modifier-name-mixedcase": "error", + "private-vars-leading-underscore": "error", + "var-name-mixedcase": "error", + "imports-on-top": "error", + "no-empty-blocks": "error", + "reason-string": "error", + "quotes": "error", + "use-forbidden-name": "error", + "visibility-modifier-order": "error", + "avoid-tx-origin": "error", + "reentrancy": "error", + "state-visibility": "error" } } diff --git a/Makefile b/Makefile index 4af283eca..73015d1b2 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,16 @@ +# ============================================================================== +# Deployment + NETWORK ?= localnet -check: - slither . --config-file ./slither.config.json +deploy-ipc: + ./ops/deploy.sh $(NETWORK) -lint: - solhint 'src/**/*.sol' +# ============================================================================== +# Running security checks within the local computer + +slither: + slither . --config-file ./slither.config.json check-gateway: docker run --rm -v $(shell pwd):/app -w /app mythril/myth:latest -v4 analyze --solc-json remappings.json ./src/Gateway.sol --solv 0.8.19 @@ -12,7 +18,17 @@ check-gateway: check-subnet: docker run --rm -v $(shell pwd):/app -w /app mythril/myth:latest -v4 analyze --solc-json remappings.json ./src/SubnetActor.sol --solv 0.8.19 -deploy-ipc: - ./ops/deploy.sh $(NETWORK) +# ============================================================================== +# Development support + +lint: + solhint 'src/**/*.sol' + +format: + npx prettier --check -w 'src/**/*.sol' 'test/*.sol' + +test: + forge test -.PHONY: deploy-ipc check lint check-subnet check-gateway \ No newline at end of file +# ============================================================================== +.PHONY: deploy-ipc lint format check-subnet slither check-gateway format \ No newline at end of file diff --git a/README.md b/README.md index 0a00bb48c..46592cb9d 100644 --- a/README.md +++ b/README.md @@ -81,3 +81,13 @@ And to generate coverage report run ```bash forge coverage ``` + +# Development + +Before committing: + +```bash +make format +make +make check +``` \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 438161b34..875319294 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,13 @@ { - "name": "filecoin-ipc-actors-fevm", - "version": "1.0.0", + "name": "ipc-solidity-actors", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "filecoin-ipc-actors-fevm", - "version": "1.0.0", - "license": "ISC", + "name": "ipc-solidity-actors", + "version": "0.0.1", + "license": "MIT OR Apache-2.0", "dependencies": { "@openzeppelin/contracts": "^4.7.3", "hardhat": "^2.15.0" diff --git a/src/Gateway.sol b/src/Gateway.sol index 7cfe3a877..96db70763 100644 --- a/src/Gateway.sol +++ b/src/Gateway.sol @@ -36,10 +36,10 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { using EpochVoteSubmissionHelper for EpochVoteTopDownSubmission; // uint8 constant MIN_CHECKPOINT_PERIOD = 10; - uint256 constant public MIN_COLLATERAL_AMOUNT = 1 ether; + uint256 public constant MIN_COLLATERAL_AMOUNT = 1 ether; /// @notice path to the current network - SubnetID private networkName; + SubnetID private _networkName; /// @notice Number of active subnets spawned from this one uint64 public totalSubnets; @@ -66,6 +66,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { uint64 public immutable topDownCheckPeriod; /// @notice BottomUpCheckpoints in the GW per epoch + // slither-disable-next-line uninitialized-state mapping(uint64 => BottomUpCheckpoint) public bottomUpCheckpoints; /// @notice nonce for bottom-up messages @@ -89,16 +90,17 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { uint256 public validatorNonce; /// @notice epoch => SubnetID => [childIndex, exists(0 - no, 1 - yes)] - mapping(uint64 => mapping(bytes32 => uint256[2])) private children; + mapping(uint64 => mapping(bytes32 => uint256[2])) private _children; /// @notice epoch => SubnetID => check => exists - mapping(uint64 => mapping(bytes32 => mapping(bytes32 => bool))) private checks; + mapping(uint64 => mapping(bytes32 => mapping(bytes32 => bool))) private _checks; /// @notice whether the contract is initialized bool public initialized; /// @notice contains voted submissions for a given epoch - mapping(uint64 => EpochVoteTopDownSubmission) private epochVoteSubmissions; + // slither-disable-next-line uninitialized-state + mapping(uint64 => EpochVoteTopDownSubmission) private _epochVoteSubmissions; error NotSystemActor(); error NotSignableAccount(); @@ -131,17 +133,23 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { error NotEnoughFundsForMembership(); modifier signableOnly() { - if (!msg.sender.isAccount()) revert NotSignableAccount(); + if (!msg.sender.isAccount()) { + revert NotSignableAccount(); + } _; } modifier systemActorOnly() { - if (!msg.sender.isSystemActor()) revert NotSystemActor(); + if (!msg.sender.isSystemActor()) { + revert NotSystemActor(); + } _; } modifier hasFee() { - if (msg.value < crossMsgFee) revert NotEnoughFee(); + if (msg.value < crossMsgFee) { + revert NotEnoughFee(); + } _; } @@ -161,16 +169,18 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { } constructor(ConstructorParams memory params) Voting(params.majorityPercentage, params.topDownCheckPeriod) { - networkName = params.networkName; + _networkName = params.networkName; minStake = MIN_COLLATERAL_AMOUNT; - bottomUpCheckPeriod = - params.bottomUpCheckPeriod < MIN_CHECKPOINT_PERIOD ? MIN_CHECKPOINT_PERIOD : params.bottomUpCheckPeriod; - topDownCheckPeriod = - params.topDownCheckPeriod < MIN_CHECKPOINT_PERIOD ? MIN_CHECKPOINT_PERIOD : params.topDownCheckPeriod; + bottomUpCheckPeriod = params.bottomUpCheckPeriod < MIN_CHECKPOINT_PERIOD + ? MIN_CHECKPOINT_PERIOD + : params.bottomUpCheckPeriod; + topDownCheckPeriod = params.topDownCheckPeriod < MIN_CHECKPOINT_PERIOD + ? MIN_CHECKPOINT_PERIOD + : params.topDownCheckPeriod; crossMsgFee = params.msgFee; // the root doesn't need to be explicitly initialized - if (networkName.isRoot()) { + if (_networkName.isRoot()) { initialized = true; } } @@ -191,13 +201,15 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice get the network name in subnet id format function getNetworkName() external view returns (SubnetID memory) { - return networkName; + return _networkName; } /// @notice initialize the contract with the genesis epoch /// @param _genesisEpoch - genesis epoch to set function initGenesisEpoch(uint64 _genesisEpoch) external systemActorOnly { - if (initialized) revert AlreadyInitialized(); + if (initialized) { + revert AlreadyInitialized(); + } genesisEpoch = _genesisEpoch; initialized = true; @@ -205,13 +217,17 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice register a subnet in the gateway. called by a subnet when it reaches the threshold stake function register() external payable { - if (msg.value < minStake) revert NotEnoughFunds(); + if (msg.value < minStake) { + revert NotEnoughFunds(); + } - SubnetID memory subnetId = networkName.createSubnetId(msg.sender); + SubnetID memory subnetId = _networkName.createSubnetId(msg.sender); (bool registered, Subnet storage subnet) = _getSubnet(subnetId); - if (registered) revert AlreadyRegisteredSubnet(); + if (registered) { + revert AlreadyRegisteredSubnet(); + } subnet.id = subnetId; subnet.stake = msg.value; @@ -223,11 +239,15 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice addStake - add collateral for an existing subnet function addStake() external payable { - if (msg.value <= 0) revert NotEnoughFunds(); + if (msg.value <= 0) { + revert NotEnoughFunds(); + } (bool registered, Subnet storage subnet) = _getSubnet(msg.sender); - if (!registered) revert NotRegisteredSubnet(); + if (!registered) { + revert NotRegisteredSubnet(); + } subnet.stake += msg.value; @@ -240,12 +260,18 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice release collateral for an existing subnet function releaseStake(uint256 amount) external nonReentrant { - if (amount == 0) revert CannotReleaseZero(); + if (amount == 0) { + revert CannotReleaseZero(); + } (bool registered, Subnet storage subnet) = _getSubnet(msg.sender); - if (!registered) revert NotRegisteredSubnet(); - if (subnet.stake < amount) revert NotEnoughFundsToRelease(); + if (!registered) { + revert NotRegisteredSubnet(); + } + if (subnet.stake < amount) { + revert NotEnoughFundsToRelease(); + } subnet.stake -= amount; @@ -257,10 +283,14 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { } function releaseRewards(uint256 amount) external nonReentrant { - if (amount == 0) revert CannotReleaseZero(); + if (amount == 0) { + revert CannotReleaseZero(); + } (bool registered, Subnet storage subnet) = _getSubnet(msg.sender); - if (!registered) revert NotRegisteredSubnet(); + if (!registered) { + revert NotRegisteredSubnet(); + } payable(subnet.id.getActor()).sendValue(amount); } @@ -269,8 +299,12 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { function kill() external { (bool registered, Subnet storage subnet) = _getSubnet(msg.sender); - if (!registered) revert NotRegisteredSubnet(); - if (subnet.circSupply > 0) revert NotEmptySubnetCircSupply(); + if (!registered) { + revert NotRegisteredSubnet(); + } + if (subnet.circSupply > 0) { + revert NotEmptySubnetCircSupply(); + } uint256 stake = subnet.stake; @@ -283,34 +317,43 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice submit a checkpoint in the gateway. Called from a subnet once the checkpoint is voted for and reaches majority function commitChildCheck(BottomUpCheckpoint calldata commit) external { - if (!initialized) revert NotInitialized(); + if (!initialized) { + revert NotInitialized(); + } if (commit.source.getActor().normalize() != msg.sender) { revert InvalidCheckpointSource(); } (, Subnet storage subnet) = _getSubnet(msg.sender); - if (subnet.status != Status.Active) revert SubnetNotActive(); - if (subnet.prevCheckpoint.epoch >= commit.epoch) revert InvalidCheckpointEpoch(); + if (subnet.status != Status.Active) { + revert SubnetNotActive(); + } + if (subnet.prevCheckpoint.epoch >= commit.epoch) { + revert InvalidCheckpointEpoch(); + } if (commit.prevHash != EMPTY_HASH) { if (commit.prevHash != subnet.prevCheckpoint.toHash()) { revert InconsistentPrevCheckpoint(); } } - (bool checkpointExists, uint64 currentEpoch, BottomUpCheckpoint storage checkpoint) = - _getCurrentBottomUpCheckpoint(); + ( + bool checkpointExists, + uint64 currentEpoch, + BottomUpCheckpoint storage checkpoint + ) = _getCurrentBottomUpCheckpoint(); // create checkpoint if not exists if (!checkpointExists) { - checkpoint.source = networkName; + checkpoint.source = _networkName; checkpoint.epoch = currentEpoch; } - checkpoint.setChildCheck(commit, children, checks, currentEpoch); + checkpoint.setChildCheck(commit, _children, _checks, currentEpoch); uint256 totalValue = 0; uint256 crossMsgLength = commit.crossMsgs.length; - for (uint256 i = 0; i < crossMsgLength;) { + for (uint256 i = 0; i < crossMsgLength; ) { totalValue += commit.crossMsgs[i].message.value; unchecked { ++i; @@ -321,7 +364,9 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { bottomUpNonce += commit.crossMsgs.length > 0 ? 1 : 0; - if (subnet.circSupply < totalValue) revert NotEnoughSubnetCircSupply(); + if (subnet.circSupply < totalValue) { + revert NotEnoughSubnetCircSupply(); + } subnet.circSupply -= totalValue; @@ -345,7 +390,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice release method locks funds in the current subnet and sends a cross message up the hierarchy to the parent gateway to release the funds function release() external payable signableOnly hasFee { - CrossMsg memory crossMsg = CrossMsgHelper.createReleaseMsg(networkName, msg.sender, msg.value - crossMsgFee); + CrossMsg memory crossMsg = CrossMsgHelper.createReleaseMsg(_networkName, msg.sender, msg.value - crossMsgFee); _commitBottomUpMsg(crossMsg); } @@ -364,12 +409,14 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { // setup the new validator set uint256 validatorsLength = validators.length; - for (uint256 validatorIndex = 0; validatorIndex < validatorsLength;) { + for (uint256 validatorIndex = 0; validatorIndex < validatorsLength; ) { address validatorAddress = validators[validatorIndex]; if (validatorAddress != address(0)) { uint256 validatorWeight = weights[validatorIndex]; - if (validatorWeight == 0) revert ValidatorWeightIsZero(); + if (validatorWeight == 0) { + revert ValidatorWeightIsZero(); + } validatorSet[validatorNonce][validatorAddress] = validatorWeight; @@ -385,7 +432,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { // to be committed. This doesn't apply to the root. // TODO: Once account abstraction is conveniently supported, there will be // no need for this initial funding of validators. - // if (block.number == 1 && !networkName.isRoot()) + // if (block.number == 1 && !_networkName.isRoot()) // payable(validatorAddress).sendValue(INITIAL_VALIDATOR_FUNDS); unchecked { @@ -398,24 +445,27 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice allows a validator to submit a batch of messages in a top-down commitment /// @param checkpoint - top-down checkpoint - function submitTopDownCheckpoint(TopDownCheckpoint calldata checkpoint) - external - signableOnly - validEpochOnly(checkpoint.epoch) - { + function submitTopDownCheckpoint( + TopDownCheckpoint calldata checkpoint + ) external signableOnly validEpochOnly(checkpoint.epoch) { uint256 validatorWeight = validatorSet[validatorNonce][msg.sender]; - if (!initialized) revert NotInitialized(); - if (validatorWeight == 0) revert NotValidator(); + if (!initialized) { + revert NotInitialized(); + } + if (validatorWeight == 0) { + revert NotValidator(); + } if (!CrossMsgHelper.isSorted(checkpoint.topDownMsgs)) { revert MessagesNotSorted(); } - EpochVoteTopDownSubmission storage voteSubmission = epochVoteSubmissions[checkpoint.epoch]; + EpochVoteTopDownSubmission storage voteSubmission = _epochVoteSubmissions[checkpoint.epoch]; // submit the vote bool shouldExecuteVote = _submitTopDownVote(voteSubmission, checkpoint, msg.sender, validatorWeight); + // slither-disable-next-line uninitialized-local CrossMsg[] memory topDownMsgs; if (shouldExecuteVote) { @@ -427,7 +477,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { (uint64 nextExecutableEpoch, bool isExecutableEpoch) = _getNextExecutableEpoch(); if (isExecutableEpoch) { - EpochVoteTopDownSubmission storage nextVoteSubmission = epochVoteSubmissions[nextExecutableEpoch]; + EpochVoteTopDownSubmission storage nextVoteSubmission = _epochVoteSubmissions[nextExecutableEpoch]; topDownMsgs = _markMostVotedSubmissionExecuted(nextVoteSubmission); } @@ -442,17 +492,19 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @param crossMsg - message to send function sendCross(SubnetID memory destination, CrossMsg memory crossMsg) external payable signableOnly hasFee { // destination is the current network, you are better off with a good ol' message, no cross needed - if (destination.equals(networkName)) { + if (destination.equals(_networkName)) { revert CannotSendCrossMsgToItself(); } - if (crossMsg.message.value != msg.value) revert NotEnoughFunds(); + if (crossMsg.message.value != msg.value) { + revert NotEnoughFunds(); + } if (crossMsg.message.to.rawAddress == address(0)) { revert InvalidCrossMsgDestinationAddress(); } // we disregard the "to" of the message. the caller is the one set as the "from" of the message. crossMsg.message.to.subnetId = destination; - crossMsg.message.from.subnetId = networkName; + crossMsg.message.from.subnetId = _networkName; crossMsg.message.from.rawAddress = msg.sender; // commit cross-message for propagation @@ -467,11 +519,13 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { function whitelistPropagator(bytes32 msgCid, address[] calldata owners) external onlyValidPostboxOwner(msgCid) { CrossMsg storage crossMsg = postbox[msgCid]; - if (crossMsg.isEmpty()) revert PostboxNotExist(); + if (crossMsg.isEmpty()) { + revert PostboxNotExist(); + } // update postbox with the new owners uint256 ownersLength = owners.length; - for (uint256 i = 0; i < ownersLength;) { + for (uint256 i = 0; i < ownersLength; ) { if (owners[i] != address(0)) { address owner = owners[i]; @@ -507,7 +561,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @param epoch - the epoch to check /// @param submitter - the validator to check function hasValidatorVotedForSubmission(uint64 epoch, address submitter) external view returns (bool) { - EpochVoteTopDownSubmission storage voteSubmission = epochVoteSubmissions[epoch]; + EpochVoteTopDownSubmission storage voteSubmission = _epochVoteSubmissions[epoch]; return voteSubmission.vote.submitters[voteSubmission.vote.nonce][submitter]; } @@ -516,11 +570,9 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @param epoch - the epoch to check /// @return exists - whether the checkpoint exists /// @return checkpoint - the checkpoint struct - function bottomUpCheckpointAtEpoch(uint64 epoch) - public - view - returns (bool exists, BottomUpCheckpoint memory checkpoint) - { + function bottomUpCheckpointAtEpoch( + uint64 epoch + ) public view returns (bool exists, BottomUpCheckpoint memory checkpoint) { checkpoint = bottomUpCheckpoints[epoch]; exists = !checkpoint.source.isEmpty(); } @@ -529,11 +581,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @param epoch - the epoch to check /// @return exists - whether the checkpoint exists /// @return hash - the hash of the checkpoint - function bottomUpCheckpointHashAtEpoch(uint64 epoch) - external - view - returns (bool, bytes32) - { + function bottomUpCheckpointHashAtEpoch(uint64 epoch) external view returns (bool, bytes32) { (bool exists, BottomUpCheckpoint memory checkpoint) = bottomUpCheckpointAtEpoch(epoch); return (exists, checkpoint.toHash()); } @@ -541,12 +589,12 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice marks a checkpoint as executed based on the last vote that reached majority /// @notice voteSubmission - the vote submission data /// @return the cross messages that should be executed - function _markMostVotedSubmissionExecuted(EpochVoteTopDownSubmission storage voteSubmission) - internal - returns (CrossMsg[] storage) - { - TopDownCheckpoint storage mostVotedSubmission = - voteSubmission.submissions[voteSubmission.vote.mostVotedSubmission]; + function _markMostVotedSubmissionExecuted( + EpochVoteTopDownSubmission storage voteSubmission + ) internal returns (CrossMsg[] storage) { + TopDownCheckpoint storage mostVotedSubmission = voteSubmission.submissions[ + voteSubmission.vote.mostVotedSubmission + ]; _markSubmissionExecuted(mostVotedSubmission.epoch); @@ -567,7 +615,12 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { bytes32 submissionHash = submission.toHash(); shouldExecuteVote = _submitVote( - voteSubmission.vote, submissionHash, submitterAddress, submitterWeight, submission.epoch, totalWeight + voteSubmission.vote, + submissionHash, + submitterAddress, + submitterWeight, + submission.epoch, + totalWeight ); // store the submission only the first time @@ -579,22 +632,26 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice Commit the cross message to storage. It outputs a flag signaling /// if the committed messages was bottom-up and some funds need to be /// burnt or if a top-down message fee needs to be distributed. - function _commitCrossMessage(CrossMsg memory crossMessage) - internal - returns (bool shouldBurn, bool shouldDistributeRewards) - { + function _commitCrossMessage( + CrossMsg memory crossMessage + ) internal returns (bool shouldBurn, bool shouldDistributeRewards) { SubnetID memory to = crossMessage.message.to.subnetId; - if (to.isEmpty()) revert InvalidCrossMsgDestinationSubnet(); - if (to.equals(networkName)) revert InvalidCrossMsgDestinationSubnet(); + if (to.isEmpty()) { + revert InvalidCrossMsgDestinationSubnet(); + } + if (to.equals(_networkName)) { + revert InvalidCrossMsgDestinationSubnet(); + } SubnetID memory from = crossMessage.message.from.subnetId; - IPCMsgType applyType = crossMessage.message.applyType(networkName); + IPCMsgType applyType = crossMessage.message.applyType(_networkName); + // slither-disable-next-line uninitialized-local bool shouldCommitBottomUp; if (applyType == IPCMsgType.BottomUp) { - shouldCommitBottomUp = !to.commonParent(from).equals(networkName); + shouldCommitBottomUp = !to.commonParent(from).equals(_networkName); } if (shouldCommitBottomUp) { @@ -623,7 +680,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { } if (shouldDistributeRewards) { - SubnetID memory toSubnetId = crossMsg.message.to.subnetId.down(networkName); + SubnetID memory toSubnetId = crossMsg.message.to.subnetId.down(_networkName); _distributeRewards(toSubnetId.getActor(), crossMsgFee); } @@ -632,11 +689,13 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice commit topdown messages for their execution in the subnet. Adds the message to the subnet struct for future execution /// @param crossMessage - the cross message to be committed function _commitTopDownMsg(CrossMsg memory crossMessage) internal { - SubnetID memory subnetId = crossMessage.message.to.subnetId.down(networkName); + SubnetID memory subnetId = crossMessage.message.to.subnetId.down(_networkName); (bool registered, Subnet storage subnet) = _getSubnet(subnetId); - if (!registered) revert NotRegisteredSubnet(); + if (!registered) { + revert NotRegisteredSubnet(); + } crossMessage.message.nonce = subnet.topDownNonce; subnet.topDownNonce += 1; @@ -644,10 +703,12 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { subnet.topDownMsgs.push(crossMessage); } - function getTopDownMsgs(SubnetID calldata subnetId) external view returns(CrossMsg[] memory) { + function getTopDownMsgs(SubnetID calldata subnetId) external view returns (CrossMsg[] memory) { (bool registered, Subnet storage subnet) = _getSubnet(subnetId); - if (!registered) revert NotRegisteredSubnet(); + if (!registered) { + revert NotRegisteredSubnet(); + } return subnet.topDownMsgs; } @@ -655,7 +716,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @notice commit bottomup messages for their execution in the subnet. Adds the message to the checkpoint for future execution /// @param crossMessage - the cross message to be committed function _commitBottomUpMsg(CrossMsg memory crossMessage) internal { - (,, BottomUpCheckpoint storage checkpoint) = _getCurrentBottomUpCheckpoint(); + (, , BottomUpCheckpoint storage checkpoint) = _getCurrentBottomUpCheckpoint(); crossMessage.message.nonce = bottomUpNonce; @@ -680,17 +741,19 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { } } - IPCMsgType applyType = crossMsg.message.applyType(networkName); + IPCMsgType applyType = crossMsg.message.applyType(_networkName); // If the cross-message destination is the current network. - if (crossMsg.message.to.subnetId.equals(networkName)) { + if (crossMsg.message.to.subnetId.equals(_networkName)) { // forwarder will always be empty subnet when we reach here from submitTopDownCheckpoint // so we check against it to not reach here in coverage if (applyType == IPCMsgType.BottomUp) { if (!forwarder.isEmpty()) { (bool registered, Subnet storage subnet) = _getSubnet(forwarder); - if (!registered) revert NotRegisteredSubnet(); + if (!registered) { + revert NotRegisteredSubnet(); + } if (subnet.appliedBottomUpNonce != crossMsg.message.nonce) { revert InvalidCrossMsgNonce(); } @@ -706,6 +769,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { appliedTopDownNonce += 1; } + // slither-disable-next-line unused-return crossMsg.execute(); return; } @@ -723,7 +787,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @param crossMsgs - the cross-net messages to apply function _applyMessages(SubnetID memory forwarder, CrossMsg[] memory crossMsgs) internal { uint256 crossMsgsLength = crossMsgs.length; - for (uint256 i = 0; i < crossMsgsLength;) { + for (uint256 i = 0; i < crossMsgsLength; ) { _applyMsg(forwarder, crossMsgs[i]); unchecked { ++i; @@ -749,7 +813,10 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @param to - the address of the target subnet contract /// @param amount - the amount of rewards to distribute function _distributeRewards(address to, uint256 amount) internal { - if (amount == 0) return; + if (amount == 0) { + return; + } + // slither-disable-next-line unused-return Address.functionCall(to.normalize(), abi.encodeWithSelector(ISubnetActor.reward.selector, amount)); } @@ -758,7 +825,7 @@ contract Gateway is IGateway, ReentrancyGuard, Voting { /// @return found whether the subnet exists /// @return subnet - the subnet struct function _getSubnet(address actor) internal view returns (bool found, Subnet storage subnet) { - SubnetID memory subnetId = networkName.createSubnetId(actor); + SubnetID memory subnetId = _networkName.createSubnetId(actor); return _getSubnet(subnetId); } diff --git a/src/SubnetActor.sol b/src/SubnetActor.sol index badf470fe..0e96e16a2 100644 --- a/src/SubnetActor.sol +++ b/src/SubnetActor.sol @@ -33,7 +33,7 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { using CrossMsgHelper for CrossMsg; /// @notice minimum collateral validators need to stake in order to join the subnet. Values get clamped to this - uint256 private constant MIN_COLLATERAL_AMOUNT = 1 ether; + uint256 public constant MIN_COLLATERAL_AMOUNT = 1 ether; /// @notice The minimum collateral required to be a validator in this subnet uint256 public immutable minActivationCollateral; @@ -72,10 +72,11 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { mapping(uint64 => BottomUpCheckpoint) public committedCheckpoints; /// @notice List of validators in the subnet - EnumerableSet.AddressSet private validators; + EnumerableSet.AddressSet private _validators; /// @notice contains voted submissions for a given epoch - mapping(uint64 => EpochVoteBottomUpSubmission) private epochVoteSubmissions; + // slither-disable-next-line uninitialized-state + mapping(uint64 => EpochVoteBottomUpSubmission) private _epochVoteSubmissions; /// @notice validator address to stake amount mapping(address => uint256) public stake; @@ -87,7 +88,7 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { mapping(address => string) public validatorNetAddresses; /// @notice ID of the parent subnet - SubnetID private parentId; + SubnetID private _parentId; /// @notice genesis block bytes public genesis; @@ -110,18 +111,23 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { error GatewayCannotBeZero(); modifier onlyGateway() { - if (msg.sender != ipcGatewayAddr) revert NotGateway(); + if (msg.sender != ipcGatewayAddr) { + revert NotGateway(); + } _; } modifier signableOnly() { - if (!msg.sender.isAccount()) revert NotAccount(); + if (!msg.sender.isAccount()) { + revert NotAccount(); + } _; } modifier notKilled() { - if (status == Status.Killed) revert SubnetAlreadyKilled(); - + if (status == Status.Killed) { + revert SubnetAlreadyKilled(); + } _; } @@ -139,21 +145,24 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { } constructor(ConstructParams memory params) Voting(params.majorityPercentage, params.bottomUpCheckPeriod) { - parentId = params.parentId; + _parentId = params.parentId; name = params.name; - if (params.ipcGatewayAddr == address(0)) revert GatewayCannotBeZero(); + if (params.ipcGatewayAddr == address(0)) { + revert GatewayCannotBeZero(); + } ipcGatewayAddr = params.ipcGatewayAddr; consensus = params.consensus; minActivationCollateral = params.minActivationCollateral < MIN_COLLATERAL_AMOUNT ? MIN_COLLATERAL_AMOUNT : params.minActivationCollateral; minValidators = params.minValidators; - topDownCheckPeriod = - params.topDownCheckPeriod < MIN_CHECKPOINT_PERIOD ? MIN_CHECKPOINT_PERIOD : params.topDownCheckPeriod; + topDownCheckPeriod = params.topDownCheckPeriod < MIN_CHECKPOINT_PERIOD + ? MIN_CHECKPOINT_PERIOD + : params.topDownCheckPeriod; bottomUpCheckPeriod = submissionPeriod; status = Status.Instantiated; genesis = params.genesis; - currentSubnetHash = parentId.createSubnetId(address(this)).toHash(); + currentSubnetHash = _parentId.createSubnetId(address(this)).toHash(); // NOTE: we currently use 0 as the genesisEpoch for subnets so checkpoints // are submitted directly from epoch 0. // In the future we can use the current epoch. This will be really @@ -163,6 +172,7 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { /* solhint-disable no-empty-blocks */ receive() external payable onlyGateway {} + /* solhint-enable no-empty-blocks */ /// @notice method that allows a validator to join the subnet @@ -170,14 +180,17 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { function join(string calldata netAddr) external payable signableOnly notKilled { uint256 validatorStake = msg.value; address validator = msg.sender; - if (validatorStake == 0) revert CollateralIsZero(); + if (validatorStake == 0) { + revert CollateralIsZero(); + } stake[validator] += validatorStake; totalStake += validatorStake; if (stake[validator] >= minActivationCollateral) { - if (!validators.contains(validator)) { - validators.add(validator); + if (!_validators.contains(validator)) { + // slither-disable-next-line unused-return + _validators.add(validator); validatorNetAddresses[validator] = netAddr; } } @@ -195,18 +208,20 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { } IGateway(ipcGatewayAddr).addStake{value: validatorStake}(); } - } /// @notice method that allows a validator to leave the subnet function leave() external nonReentrant signableOnly notKilled { uint256 amount = stake[msg.sender]; - if (amount == 0) revert NotValidator(); + if (amount == 0) { + revert NotValidator(); + } stake[msg.sender] = 0; totalStake -= amount; - validators.remove(msg.sender); + // slither-disable-next-line unused-return + _validators.remove(msg.sender); if (status == Status.Active) { if (totalStake < minActivationCollateral) { status = Status.Inactive; @@ -220,7 +235,9 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { /// @notice method that allows the subnet no be killed after all validators leave function kill() external signableOnly notKilled { - if (validators.length() != 0 || totalStake != 0) revert NotAllValidatorsHaveLeft(); + if (_validators.length() != 0 || totalStake != 0) { + revert NotAllValidatorsHaveLeft(); + } status = Status.Killed; @@ -229,17 +246,23 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { /// @notice methods that allows a validator to submit a checkpoint (batch of messages) and vote for it with it's own voting power. /// @param checkpoint - the batch messages data - function submitCheckpoint(BottomUpCheckpoint calldata checkpoint) - external - signableOnly - validEpochOnly(checkpoint.epoch) - { - if (status != Status.Active) revert SubnetNotActive(); - if (!validators.contains(msg.sender)) revert NotValidator(); - if (checkpoint.source.toHash() != currentSubnetHash) revert WrongCheckpointSource(); - if (!CrossMsgHelper.isSorted(checkpoint.crossMsgs)) revert MessagesNotSorted(); - - EpochVoteBottomUpSubmission storage voteSubmission = epochVoteSubmissions[checkpoint.epoch]; + function submitCheckpoint( + BottomUpCheckpoint calldata checkpoint + ) external signableOnly validEpochOnly(checkpoint.epoch) { + if (status != Status.Active) { + revert SubnetNotActive(); + } + if (!_validators.contains(msg.sender)) { + revert NotValidator(); + } + if (checkpoint.source.toHash() != currentSubnetHash) { + revert WrongCheckpointSource(); + } + if (!CrossMsgHelper.isSorted(checkpoint.crossMsgs)) { + revert MessagesNotSorted(); + } + + EpochVoteBottomUpSubmission storage voteSubmission = _epochVoteSubmissions[checkpoint.epoch]; // submit the vote bool shouldExecuteVote = _submitBottomUpVote(voteSubmission, checkpoint, msg.sender, stake[msg.sender]); @@ -251,7 +274,7 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { (uint64 nextExecutableEpoch, bool isExecutableEpoch) = _getNextExecutableEpoch(); if (isExecutableEpoch) { - EpochVoteBottomUpSubmission storage nextVoteSubmission = epochVoteSubmissions[nextExecutableEpoch]; + EpochVoteBottomUpSubmission storage nextVoteSubmission = _epochVoteSubmissions[nextExecutableEpoch]; _commitCheckpoint(nextVoteSubmission); } @@ -260,15 +283,19 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { /// @notice method that distributes the rewards for the subnet to validators. function reward(uint256 amount) external onlyGateway { - uint256 validatorsLength = validators.length(); + uint256 validatorsLength = _validators.length(); - if (validatorsLength == 0) revert NoValidatorsInSubnet(); - if (amount < validatorsLength) revert NotEnoughBalanceForRewards(); + if (validatorsLength == 0) { + revert NoValidatorsInSubnet(); + } + if (amount < validatorsLength) { + revert NotEnoughBalanceForRewards(); + } uint256 rewardAmount = amount / validatorsLength; - for (uint256 i = 0; i < validatorsLength;) { - accumulatedRewards[validators.at(i)] += rewardAmount; + for (uint256 i = 0; i < validatorsLength; ) { + accumulatedRewards[_validators.at(i)] += rewardAmount; unchecked { ++i; } @@ -279,7 +306,9 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { function withdraw() external signableOnly { uint256 amount = accumulatedRewards[msg.sender]; - if (amount == 0) revert NoRewardToWithdraw(); + if (amount == 0) { + revert NoRewardToWithdraw(); + } accumulatedRewards[msg.sender] = 0; @@ -290,28 +319,28 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { /// @notice get the parent subnet id function getParent() external view returns (SubnetID memory) { - return parentId; + return _parentId; } /// @notice get validator count function validatorCount() external view returns (uint256) { - return validators.length(); + return _validators.length(); } /// @notice get validator at index /// @param index - the index of the validator set function validatorAt(uint256 index) external view returns (address) { - return validators.at(index); + return _validators.at(index); } /// @notice get all the validators in the subnet. /// TODO: we can introduce pagination function getValidators() external view returns (address[] memory) { - uint256 length = validators.length(); + uint256 length = _validators.length(); address[] memory result = new address[](length); - for (uint256 i = 0; i < length;) { - result[i] = validators.at(i); + for (uint256 i = 0; i < length; ) { + result[i] = _validators.at(i); unchecked { ++i; } @@ -324,7 +353,7 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { /// @param epoch - the epoch to check /// @param submitter - the validator to check function hasValidatorVotedForSubmission(uint64 epoch, address submitter) external view returns (bool) { - EpochVoteBottomUpSubmission storage voteSubmission = epochVoteSubmissions[epoch]; + EpochVoteBottomUpSubmission storage voteSubmission = _epochVoteSubmissions[epoch]; return voteSubmission.vote.submitters[voteSubmission.vote.nonce][submitter]; } @@ -342,7 +371,12 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { bytes32 submissionHash = submission.toHash(); shouldExecuteVote = _submitVote( - voteSubmission.vote, submissionHash, submitterAddress, submitterWeight, submission.epoch, totalStake + voteSubmission.vote, + submissionHash, + submitterAddress, + submitterWeight, + submission.epoch, + totalStake ); // store the submission only the first time @@ -352,11 +386,9 @@ contract SubnetActor is ISubnetActor, ReentrancyGuard, Voting { } /// @notice method that returns the most voted submission for a checkpoint - function _getMostVotedSubmission(EpochVoteBottomUpSubmission storage voteSubmission) - internal - view - returns (BottomUpCheckpoint storage) - { + function _getMostVotedSubmission( + EpochVoteBottomUpSubmission storage voteSubmission + ) internal view returns (BottomUpCheckpoint storage) { return voteSubmission.submissions[voteSubmission.vote.mostVotedSubmission]; } diff --git a/src/SubnetRegistry.sol b/src/SubnetRegistry.sol index 86c819552..9047b3600 100644 --- a/src/SubnetRegistry.sol +++ b/src/SubnetRegistry.sol @@ -24,7 +24,9 @@ contract SubnetRegistry { } function newSubnetActor(SubnetActor.ConstructParams calldata _params) external returns (address subnetAddr) { - if (_params.ipcGatewayAddr != gateway) revert NotSameGateway(); + if (_params.ipcGatewayAddr != gateway) { + revert NotSameGateway(); + } subnetAddr = address(new SubnetActor(_params)); diff --git a/src/Voting.sol b/src/Voting.sol index 1c1b05cd9..faf665f04 100644 --- a/src/Voting.sol +++ b/src/Voting.sol @@ -13,7 +13,7 @@ abstract contract Voting { using EpochVoteSubmissionHelper for EpochVoteSubmission; /// @notice minimum checkpoint period. Values get clamped to this - uint8 constant public MIN_CHECKPOINT_PERIOD = 10; + uint8 public constant MIN_CHECKPOINT_PERIOD = 10; /// @notice percent approvals needed to reach consensus uint8 public immutable majorityPercentage; @@ -38,7 +38,9 @@ abstract contract Voting { error ValidatorAlreadyVoted(); modifier validEpochOnly(uint64 epoch) { - if (epoch <= lastVotingExecutedEpoch) revert EpochAlreadyExecuted(); + if (epoch <= lastVotingExecutedEpoch) { + revert EpochAlreadyExecuted(); + } if (epoch > genesisEpoch) { if ((epoch - genesisEpoch) % submissionPeriod != 0) { revert EpochNotVotable(); @@ -48,7 +50,9 @@ abstract contract Voting { } constructor(uint8 _majorityPercentage, uint64 _submissionPeriod) { - if (_majorityPercentage > 100) revert InvalidMajorityPercentage(); + if (_majorityPercentage > 100) { + revert InvalidMajorityPercentage(); + } majorityPercentage = _majorityPercentage; submissionPeriod = _submissionPeriod < MIN_CHECKPOINT_PERIOD ? MIN_CHECKPOINT_PERIOD : _submissionPeriod; @@ -59,11 +63,10 @@ abstract contract Voting { /// @notice returns the current checkpoint execution status based on the current vote /// @param vote - the vote submission data /// @param totalWeight - the total voting power of the validators - function _deriveExecutionStatus(EpochVoteSubmission storage vote, uint256 totalWeight) - internal - view - returns (VoteExecutionStatus) - { + function _deriveExecutionStatus( + EpochVoteSubmission storage vote, + uint256 totalWeight + ) internal view returns (VoteExecutionStatus) { uint256 threshold = (totalWeight * majorityPercentage) / 100; uint256 mostVotedWeight = vote.getMostVotedWeight(); @@ -102,7 +105,9 @@ abstract contract Voting { /// @param epoch - the epoch to mark as executed function _markSubmissionExecuted(uint64 epoch) internal { // epoch not the next executable epoch - if (!_isNextExecutableEpoch(epoch)) return; + if (!_isNextExecutableEpoch(epoch)) { + return; + } // epoch not the next executable epoch in the queue if (executableQueue.contains(epoch)) { @@ -150,7 +155,9 @@ abstract contract Voting { uint256 totalWeight ) internal returns (bool shouldExecuteVote) { uint256 nonce = vote.nonce; - if (vote.submitters[nonce][submitterAddress]) revert ValidatorAlreadyVoted(); + if (vote.submitters[nonce][submitterAddress]) { + revert ValidatorAlreadyVoted(); + } vote.submitters[nonce][submitterAddress] = true; vote.totalSubmissionWeight += submitterWeight; diff --git a/src/enums/ConsensusType.sol b/src/enums/ConsensusType.sol index 084d3cb8c..ba174ad75 100644 --- a/src/enums/ConsensusType.sol +++ b/src/enums/ConsensusType.sol @@ -3,4 +3,6 @@ pragma solidity 0.8.18; /// @title Subnet Consensus Type enum /// @author LimeChain team -enum ConsensusType {Mir} +enum ConsensusType { + Mir +} diff --git a/src/lib/CheckpointHelper.sol b/src/lib/CheckpointHelper.sol index 96fd5b0f6..93937d974 100644 --- a/src/lib/CheckpointHelper.sol +++ b/src/lib/CheckpointHelper.sol @@ -10,22 +10,23 @@ import "../constants/Constants.sol"; library CheckpointHelper { using SubnetIDHelper for SubnetID; - bytes32 constant private EMPTY_TOPDOWNCHECKPOINT_HASH = + bytes32 public constant EMPTY_TOPDOWNCHECKPOINT_HASH = keccak256(abi.encode(TopDownCheckpoint({epoch: 0, topDownMsgs: new CrossMsg[](0)}))); - bytes32 constant private EMPTY_BOTTOMUPCHECKPOINT_HASH = keccak256( - abi.encode( - BottomUpCheckpoint({ - source: SubnetID(0, new address[](0)), - epoch: 0, - fee: 0, - crossMsgs: new CrossMsg[](0), - children: new ChildCheck[](0), - prevHash: EMPTY_HASH, - proof: new bytes(0) - }) - ) - ); + bytes32 public constant EMPTY_BOTTOMUPCHECKPOINT_HASH = + keccak256( + abi.encode( + BottomUpCheckpoint({ + source: SubnetID(0, new address[](0)), + epoch: 0, + fee: 0, + crossMsgs: new CrossMsg[](0), + children: new ChildCheck[](0), + prevHash: EMPTY_HASH, + proof: new bytes(0) + }) + ) + ); function toHash(BottomUpCheckpoint memory bottomupCheckpoint) public pure returns (bytes32) { return keccak256(abi.encode(bottomupCheckpoint)); diff --git a/src/lib/CrossMsgHelper.sol b/src/lib/CrossMsgHelper.sol index 7b612c167..6af3d6e6e 100644 --- a/src/lib/CrossMsgHelper.sol +++ b/src/lib/CrossMsgHelper.sol @@ -13,56 +13,59 @@ library CrossMsgHelper { using SubnetIDHelper for SubnetID; using FilAddress for address; - bytes32 public constant EMPTY_CROSS_MSG = keccak256( - abi.encode( + bytes32 public constant EMPTY_CROSS_MSG = + keccak256( + abi.encode( + CrossMsg({ + message: StorableMsg({ + from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + value: 0, + nonce: 0, + method: METHOD_SEND, + params: EMPTY_BYTES + }), + wrapped: false + }) + ) + ); + + function createReleaseMsg( + SubnetID calldata subnet, + address signer, + uint256 value + ) public pure returns (CrossMsg memory) { + return CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - value: 0, + from: IPCAddress({subnetId: subnet, rawAddress: BURNT_FUNDS_ACTOR}), + to: IPCAddress({subnetId: subnet.getParentSubnet(), rawAddress: signer}), + value: value, nonce: 0, method: METHOD_SEND, params: EMPTY_BYTES }), wrapped: false - }) - ) - ); - - function createReleaseMsg(SubnetID calldata subnet, address signer, uint256 value) - public - pure - returns (CrossMsg memory) - { - return CrossMsg({ - message: StorableMsg({ - from: IPCAddress({subnetId: subnet, rawAddress: BURNT_FUNDS_ACTOR}), - to: IPCAddress({subnetId: subnet.getParentSubnet(), rawAddress: signer}), - value: value, - nonce: 0, - method: METHOD_SEND, - params: EMPTY_BYTES - }), - wrapped: false - }); + }); } - function createFundMsg(SubnetID calldata subnet, address signer, uint256 value) - public - pure - returns (CrossMsg memory) - { - return CrossMsg({ - message: StorableMsg({ - from: IPCAddress({subnetId: subnet.getParentSubnet(), rawAddress: signer}), - to: IPCAddress({subnetId: subnet, rawAddress: signer}), - value: value, - nonce: 0, - method: METHOD_SEND, - params: EMPTY_BYTES - }), - wrapped: false - }); + function createFundMsg( + SubnetID calldata subnet, + address signer, + uint256 value + ) public pure returns (CrossMsg memory) { + return + CrossMsg({ + message: StorableMsg({ + from: IPCAddress({subnetId: subnet.getParentSubnet(), rawAddress: signer}), + to: IPCAddress({subnetId: subnet, rawAddress: signer}), + value: value, + nonce: 0, + method: METHOD_SEND, + params: EMPTY_BYTES + }), + wrapped: false + }); } function toHash(CrossMsg memory crossMsg) internal pure returns (bytes32) { @@ -105,7 +108,7 @@ library CrossMsgHelper { function isSorted(CrossMsg[] calldata crossMsgs) external pure returns (bool) { uint256 prevNonce = 0; uint256 length = crossMsgs.length; - for (uint256 i = 0; i < length;) { + for (uint256 i = 0; i < length; ) { uint256 nonce = crossMsgs[i].message.nonce; if (prevNonce >= nonce) { diff --git a/src/lib/ExecutableQueueHelper.sol b/src/lib/ExecutableQueueHelper.sol index d771f62aa..f5c5ff80f 100644 --- a/src/lib/ExecutableQueueHelper.sol +++ b/src/lib/ExecutableQueueHelper.sol @@ -5,7 +5,9 @@ import "../structs/ExecutableQueue.sol"; library ExecutableQueueHelper { function push(ExecutableQueue storage queue, uint64 epoch) public { - if (epoch == 0) return; + if (epoch == 0) { + return; + } if (queue.first == 0 || queue.first > epoch) { queue.first = epoch; @@ -18,7 +20,9 @@ library ExecutableQueueHelper { } function remove(ExecutableQueue storage queue, uint64 epoch) public { - if (!contains(queue, epoch)) return; + if (!contains(queue, epoch)) { + return; + } delete queue.epochs[epoch]; diff --git a/src/lib/StorableMsgHelper.sol b/src/lib/StorableMsgHelper.sol index 10fd685a2..8e93b355f 100644 --- a/src/lib/StorableMsgHelper.sol +++ b/src/lib/StorableMsgHelper.sol @@ -11,24 +11,21 @@ import "../enums/IPCMsgType.sol"; library StorableMsgHelper { using SubnetIDHelper for SubnetID; - bytes32 public constant EMPTY_STORABLE_MESSAGE_HASH = keccak256( - abi.encode( - StorableMsg({ - from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - value: 0, - nonce: 0, - method: METHOD_SEND, - params: EMPTY_BYTES - }) - ) - ); + bytes32 public constant EMPTY_STORABLE_MESSAGE_HASH = + keccak256( + abi.encode( + StorableMsg({ + from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + value: 0, + nonce: 0, + method: METHOD_SEND, + params: EMPTY_BYTES + }) + ) + ); - function applyType(StorableMsg calldata message, SubnetID calldata currentSubnet) - public - pure - returns (IPCMsgType) - { + function applyType(StorableMsg calldata message, SubnetID calldata currentSubnet) public pure returns (IPCMsgType) { SubnetID memory toSubnet = message.to.subnetId; SubnetID memory fromSubnet = message.from.subnetId; SubnetID memory currentParentSubnet = currentSubnet.commonParent(toSubnet); diff --git a/src/lib/SubnetIDHelper.sol b/src/lib/SubnetIDHelper.sol index fb2cab66e..f3ba4701d 100644 --- a/src/lib/SubnetIDHelper.sol +++ b/src/lib/SubnetIDHelper.sol @@ -12,14 +12,16 @@ library SubnetIDHelper { error NoParentForSubnet(); error EmptySubnet(); - bytes32 private constant EMPTY_SUBNET_HASH = keccak256(abi.encode(SubnetID({root: 0, route: new address[](0)}))); + bytes32 public constant EMPTY_SUBNET_HASH = keccak256(abi.encode(SubnetID({root: 0, route: new address[](0)}))); function getParentSubnet(SubnetID memory subnet) public pure returns (SubnetID memory) { - if (subnet.route.length == 0) revert NoParentForSubnet(); + if (subnet.route.length == 0) { + revert NoParentForSubnet(); + } address[] memory route = new address[](subnet.route.length - 1); uint256 routeLength = route.length; - for (uint256 i = 0; i < routeLength;) { + for (uint256 i = 0; i < routeLength; ) { route[i] = subnet.route[i]; unchecked { ++i; @@ -31,7 +33,7 @@ library SubnetIDHelper { function toString(SubnetID calldata subnet) public pure returns (string memory) { string memory route = string(abi.encodePacked("/r", Strings.toString(subnet.root))); - for (uint256 i = 0; i < subnet.route.length;) { + for (uint256 i = 0; i < subnet.route.length; ) { route = string.concat(route, "/"); route = string.concat(route, subnet.route[i].toHexString()); unchecked { @@ -50,7 +52,7 @@ library SubnetIDHelper { newSubnet.root = subnet.root; newSubnet.route = new address[](subnet.route.length + 1); uint256 routeLength = subnet.route.length; - for (uint256 i = 0; i < routeLength;) { + for (uint256 i = 0; i < routeLength; ) { newSubnet.route[i] = subnet.route[i]; unchecked { ++i; @@ -61,7 +63,9 @@ library SubnetIDHelper { } function getActor(SubnetID calldata subnet) public pure returns (address) { - if (subnet.route.length == 0) return address(0); + if (subnet.route.length == 0) { + return address(0); + } return subnet.route[subnet.route.length - 1]; } @@ -71,8 +75,12 @@ library SubnetIDHelper { } function equals(SubnetID calldata subnet1, SubnetID calldata subnet2) public pure returns (bool) { - if (subnet1.root != subnet2.root) return false; - if (subnet1.route.length != subnet2.route.length) return false; + if (subnet1.root != subnet2.root) { + return false; + } + if (subnet1.route.length != subnet2.route.length) { + return false; + } return toHash(subnet1) == toHash(subnet2); } @@ -91,10 +99,12 @@ library SubnetIDHelper { ++i; } } - if (i == 0) return SubnetID({root: subnet1.root, route: new address[](0)}); + if (i == 0) { + return SubnetID({root: subnet1.root, route: new address[](0)}); + } address[] memory route = new address[](i); - for (uint256 j = 0; j < i;) { + for (uint256 j = 0; j < i; ) { route[j] = subnet1.route[j]; unchecked { ++j; @@ -127,7 +137,7 @@ library SubnetIDHelper { address[] memory route = new address[](i); - for (uint256 j = 0; j < i;) { + for (uint256 j = 0; j < i; ) { route[j] = subnet1.route[j]; unchecked { ++j; diff --git a/test/CheckpointHelper.t.sol b/test/CheckpointHelper.t.sol index 3e75269d8..94411ebf2 100644 --- a/test/CheckpointHelper.t.sol +++ b/test/CheckpointHelper.t.sol @@ -63,7 +63,7 @@ contract CheckpointHelperTest is Test { function isSorted(BottomUpCheckpoint memory _checkpoint) public pure returns (bool) { if (_checkpoint.crossMsgs.length < 2) return true; - for (uint256 i = 1; i < _checkpoint.crossMsgs.length;) { + for (uint256 i = 1; i < _checkpoint.crossMsgs.length; ) { if (_checkpoint.crossMsgs[i].message.nonce <= _checkpoint.crossMsgs[i - 1].message.nonce) return false; unchecked { diff --git a/test/CrossMsgHelper.t.sol b/test/CrossMsgHelper.t.sol index 175f6962a..9da0c42dc 100644 --- a/test/CrossMsgHelper.t.sol +++ b/test/CrossMsgHelper.t.sol @@ -244,17 +244,18 @@ contract CrossMsgHelperTest is Test { } function createCrossMsg(uint64 nonce) internal pure returns (CrossMsg memory) { - return CrossMsg({ - message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - value: 0, - nonce: nonce, - method: METHOD_SEND, - params: EMPTY_BYTES - }), - wrapped: false - }); + return + CrossMsg({ + message: StorableMsg({ + from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + value: 0, + nonce: nonce, + method: METHOD_SEND, + params: EMPTY_BYTES + }), + wrapped: false + }); } function createCrossMsgs(uint256 length, uint64 nonce) internal pure returns (CrossMsg[] memory _crossMsgs) { diff --git a/test/EpochVoteSubmissionHelper.t.sol b/test/EpochVoteSubmissionHelper.t.sol index a59de6330..d06822a15 100644 --- a/test/EpochVoteSubmissionHelper.t.sol +++ b/test/EpochVoteSubmissionHelper.t.sol @@ -75,8 +75,8 @@ contract EpochVoteSubmissionHelperTest is Test { voteSubmission.mostVotedSubmission = submissionHash1; if ( - voteSubmission.submissionWeights[nonce][submissionHash1] - < voteSubmission.submissionWeights[nonce][submissionHash2] + voteSubmission.submissionWeights[nonce][submissionHash1] < + voteSubmission.submissionWeights[nonce][submissionHash2] ) { voteSubmission.mostVotedSubmission = submissionHash2; } diff --git a/test/Gateway.t.sol b/test/Gateway.t.sol index e357ff4a4..d70b3c117 100644 --- a/test/Gateway.t.sol +++ b/test/Gateway.t.sol @@ -240,7 +240,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { registerSubnet(registerAmount, subnetAddress); addStake(stakeAmount, subnetAddress); - (, uint256 totalStaked,,,,) = getSubnet(subnetAddress); + (, uint256 totalStaked, , , , ) = getSubnet(subnetAddress); require(totalStaked == totalAmount); } @@ -256,13 +256,13 @@ contract GatewayDeploymentTest is StdInvariant, Test { registerSubnet(registerAmount, subnetAddress); gw.releaseStake(registerAmount); - (,,,,, Status statusInactive) = getSubnet(subnetAddress); + (, , , , , Status statusInactive) = getSubnet(subnetAddress); require(statusInactive == Status.Inactive); vm.deal(subnetAddress, stakeAmount); addStake(stakeAmount, subnetAddress); - (, uint256 staked,,,, Status statusActive) = getSubnet(subnetAddress); + (, uint256 staked, , , , Status statusActive) = getSubnet(subnetAddress); require(staked == stakeAmount); require(statusActive == Status.Active); @@ -282,7 +282,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { vm.deal(subnetAddress, stakeAmount); addStake(stakeAmount, subnetAddress); - (, uint256 staked,,,, Status status) = getSubnet(subnetAddress); + (, uint256 staked, , , , Status status) = getSubnet(subnetAddress); require(staked == stakeAmount); require(status == Status.Inactive); @@ -307,7 +307,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { expectedStakedAmount += singleStakeAmount; } - (, uint256 totalStake,,,,) = getSubnet(subnetAddress); + (, uint256 totalStake, , , , ) = getSubnet(subnetAddress); require(totalStake == expectedStakedAmount); } @@ -342,7 +342,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.releaseStake(fullAmount); - (, uint256 stake,,,, Status status) = getSubnet(subnetAddress); + (, uint256 stake, , , , Status status) = getSubnet(subnetAddress); require(stake == 0); require(status == Status.Inactive); @@ -357,7 +357,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.releaseStake(MIN_COLLATERAL_AMOUNT / 2); - (, uint256 stake,,,, Status status) = getSubnet(subnetAddress); + (, uint256 stake, , , , Status status) = getSubnet(subnetAddress); require(stake == MIN_COLLATERAL_AMOUNT / 2, "stake == MIN_COLLATERAL_AMOUNT / 2"); require(status == Status.Inactive, "status == Status.Inactive"); } @@ -378,7 +378,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.releaseStake(partialAmount); - (, uint256 stake,,,, Status status) = getSubnet(subnetAddress); + (, uint256 stake, , , , Status status) = getSubnet(subnetAddress); require(stake == registerAmount); require(status == Status.Active); @@ -424,7 +424,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.releaseStake(10); - (, uint256 stake,,,, Status status) = getSubnet(subnetAddress); + (, uint256 stake, , , , Status status) = getSubnet(subnetAddress); require(stake == MIN_COLLATERAL_AMOUNT - 10, "stake should be MIN_COLLATERAL_AMOUNT - 10"); require(status == Status.Inactive, "status should be Inactive"); @@ -467,8 +467,9 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.kill(); - (SubnetID memory id, uint256 stake, uint256 nonce,, uint256 circSupply, Status status) = - getSubnet(subnetAddress); + (SubnetID memory id, uint256 stake, uint256 nonce, , uint256 circSupply, Status status) = getSubnet( + subnetAddress + ); require(id.toHash() == SubnetID(0, new address[](0)).toHash()); require(stake == 0); @@ -557,11 +558,11 @@ contract GatewayDeploymentTest is StdInvariant, Test { vm.expectCall(subnetAddress, 0, abi.encodeWithSelector(ISubnetActor.reward.selector, checkpoint.fee), 1); - (,,,, uint256 circSupplyBefore,) = getSubnet(subnetAddress); + (, , , , uint256 circSupplyBefore, ) = getSubnet(subnetAddress); gw.commitChildCheck(checkpoint); - (,, uint256 appliedBottomUpNonce,, uint256 circSupplyAfter,) = getSubnet(subnetAddress); + (, , uint256 appliedBottomUpNonce, , uint256 circSupplyAfter, ) = getSubnet(subnetAddress); require(gw.bottomUpNonce() == 1); require(appliedBottomUpNonce == 1); @@ -865,7 +866,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { vm.startPrank(invalidAccount); vm.deal(invalidAccount, fundAmount + 1); - (SubnetID memory subnetId,,,,,) = getSubnet(address(sa)); + (SubnetID memory subnetId, , , , , ) = getSubnet(address(sa)); vm.expectRevert(NotSignableAccount.selector); @@ -900,7 +901,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { vm.startPrank(funderAddress); vm.deal(funderAddress, 1 ether); - (SubnetID memory subnetId,,,,,) = getSubnet(address(sa)); + (SubnetID memory subnetId, , , , , ) = getSubnet(address(sa)); vm.expectRevert(NotEnoughFee.selector); @@ -1045,8 +1046,14 @@ contract GatewayDeploymentTest is StdInvariant, Test { SubnetID({root: 0, route: new address[](0)}), CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), - to: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), + from: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), + to: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), value: CROSS_MSG_FEE + 1, nonce: 0, method: METHOD_SEND, @@ -1067,8 +1074,14 @@ contract GatewayDeploymentTest is StdInvariant, Test { SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), - to: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), + from: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), + to: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), value: CROSS_MSG_FEE + 1, nonce: 0, method: METHOD_SEND, @@ -1090,8 +1103,14 @@ contract GatewayDeploymentTest is StdInvariant, Test { destination, CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), - to: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), + from: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), + to: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), value: CROSS_MSG_FEE + 1, nonce: 0, method: METHOD_SEND, @@ -1113,8 +1132,14 @@ contract GatewayDeploymentTest is StdInvariant, Test { destination, CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), - to: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), + from: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), + to: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), value: 5, nonce: 0, method: METHOD_SEND, @@ -1136,7 +1161,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { destination, CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), + from: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), to: IPCAddress({ subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: address(0) @@ -1162,7 +1190,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { destination, CrossMsg({ message: StorableMsg({ - from: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: caller}), + from: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: caller + }), to: IPCAddress({ subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: address(0) @@ -1208,7 +1239,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.sendCross{value: CROSS_MSG_FEE + 1}(destination, crossMsg); - (SubnetID memory id,, uint256 nonce,, uint256 circSupply,) = getSubnet(address(this)); + (SubnetID memory id, , uint256 nonce, , uint256 circSupply, ) = getSubnet(address(this)); require(crossMsg.message.applyType(gw.getNetworkName()) == IPCMsgType.TopDown); require(id.equals(destination)); @@ -1218,8 +1249,8 @@ contract GatewayDeploymentTest is StdInvariant, Test { require(gw.appliedTopDownNonce() == 1); } - function reward(uint256 amount) external { - console.log("reward method called"); + function reward(uint256 amount) external view { + console.log("reward method called with %d", amount); } function test_SendCross_Works_BottomUp_CurrentNetworkNotCommonParent() public { @@ -1313,8 +1344,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { CrossMsg[] memory topDownMsgs = new CrossMsg[](1); topDownMsgs[0] = crossMsg; - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(TOPDOWN_VALIDATOR_1); vm.deal(TOPDOWN_VALIDATOR_1, 1); gw.submitTopDownCheckpoint(checkpoint); @@ -1435,7 +1468,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { CrossMsg memory crossMsg = CrossMsg({ message: StorableMsg({ from: IPCAddress({subnetId: gw.getNetworkName().createSubnetId(caller), rawAddress: caller}), - to: IPCAddress({subnetId: gw.getNetworkName().createSubnetId(address(this)), rawAddress: address(this)}), + to: IPCAddress({ + subnetId: gw.getNetworkName().createSubnetId(address(this)), + rawAddress: address(this) + }), value: CROSS_MSG_FEE + 1, nonce: 0, method: METHOD_SEND, @@ -1450,8 +1486,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { CrossMsg[] memory topDownMsgs = new CrossMsg[](1); topDownMsgs[0] = crossMsg; - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validators[0]); gw.submitTopDownCheckpoint(checkpoint); @@ -1526,8 +1564,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { } function test_SubmitTopDownCheckpoint_Fails_NotSignableAccount() public { - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); address validator = vm.addr(400); vm.prank(validator); @@ -1540,8 +1580,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { addValidator(validator, 100); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); vm.prank(validator); vm.deal(validator, 1 ether); @@ -1557,8 +1599,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { addValidator(validator); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD + 1, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD + 1, + topDownMsgs: new CrossMsg[](0) + }); vm.prank(validator); vm.expectRevert(EpochNotVotable.selector); @@ -1569,8 +1613,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { function test_SubmitTopDownCheckpoint_Fails_ValidatorAlreadyVoted() public { address[] memory validators = setupValidators(); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); vm.prank(validators[0]); gw.submitTopDownCheckpoint(checkpoint); @@ -1599,8 +1645,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { addValidator(validator, 100); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); vm.prank(validator); vm.deal(validator, 1); @@ -1609,8 +1657,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { } function test_SubmitTopDownCheckpoint_Fails_NotValidator() public { - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); address nonValidator = vm.addr(400); vm.prank(nonValidator); @@ -1646,8 +1696,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validators[0]); vm.expectRevert(MessagesNotSorted.selector); @@ -1673,8 +1725,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validator); vm.expectRevert(InvalidCrossMsgDestinationAddress.selector); @@ -1700,8 +1754,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validator); vm.expectRevert(NotEnoughBalance.selector); @@ -1727,8 +1783,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validator); vm.deal(validator, 1); @@ -1756,8 +1814,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validator); vm.deal(validator, 1); @@ -1781,8 +1841,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { }), wrapped: false }); - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validators[0]); gw.submitTopDownCheckpoint(checkpoint); @@ -1827,8 +1889,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { }); } - TopDownCheckpoint memory checkpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validators[0]); gw.submitTopDownCheckpoint(checkpoint); @@ -1886,10 +1950,14 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory currentCheckpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); - TopDownCheckpoint memory futureCheckpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD + 10, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory currentCheckpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); + TopDownCheckpoint memory futureCheckpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD + 10, + topDownMsgs: topDownMsgs + }); // reaching consensus for the future checkpoint, so it should be added to the queue vm.prank(validators[0]); @@ -1938,8 +2006,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { }); uint64 nextEpoch = DEFAULT_CHECKPOINT_PERIOD + 50; - TopDownCheckpoint memory currentCheckpoint = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); + TopDownCheckpoint memory currentCheckpoint = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); TopDownCheckpoint memory futureCheckpoint = TopDownCheckpoint({epoch: nextEpoch, topDownMsgs: topDownMsgs}); // reaching consensus for the future checkpoint, so it should be added to the queue @@ -1990,13 +2060,19 @@ contract GatewayDeploymentTest is StdInvariant, Test { wrapped: false }); - TopDownCheckpoint memory checkpoint1 = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: new CrossMsg[](0)}); - TopDownCheckpoint memory checkpoint2 = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint1 = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: new CrossMsg[](0) + }); + TopDownCheckpoint memory checkpoint2 = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); topDownMsgs[0].wrapped = true; - TopDownCheckpoint memory checkpoint3 = - TopDownCheckpoint({epoch: DEFAULT_CHECKPOINT_PERIOD, topDownMsgs: topDownMsgs}); + TopDownCheckpoint memory checkpoint3 = TopDownCheckpoint({ + epoch: DEFAULT_CHECKPOINT_PERIOD, + topDownMsgs: topDownMsgs + }); vm.prank(validators[0]); gw.submitTopDownCheckpoint(checkpoint1); @@ -2061,7 +2137,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { function fund(address funderAddress, uint256 fundAmount) internal { uint256 fundAmountWithSubtractedFee = fundAmount - gw.crossMsgFee(); - (SubnetID memory subnetId,, uint256 nonceBefore,, uint256 circSupplyBefore,) = getSubnet(address(sa)); + (SubnetID memory subnetId, , uint256 nonceBefore, , uint256 circSupplyBefore, ) = getSubnet(address(sa)); uint256 expectedTopDownMsgsLenght = gw.getSubnetTopDownMsgsLength(subnetId) + 1; uint256 expectedNonce = nonceBefore + 1; @@ -2073,7 +2149,7 @@ contract GatewayDeploymentTest is StdInvariant, Test { gw.fund{value: fundAmount}(subnetId); - (,, uint256 nonce,, uint256 circSupply,) = getSubnet(address(sa)); + (, , uint256 nonce, , uint256 circSupply, ) = getSubnet(address(sa)); require(gw.getSubnetTopDownMsgsLength(subnetId) == expectedTopDownMsgsLenght); @@ -2086,12 +2162,12 @@ contract GatewayDeploymentTest is StdInvariant, Test { require(topDownMsg.message.nonce == msgIndex); require(topDownMsg.message.value == fundAmountWithSubtractedFee); require( - keccak256(abi.encode(topDownMsg.message.to)) - == keccak256(abi.encode(IPCAddress({subnetId: subnetId, rawAddress: funderAddress}))) + keccak256(abi.encode(topDownMsg.message.to)) == + keccak256(abi.encode(IPCAddress({subnetId: subnetId, rawAddress: funderAddress}))) ); require( - keccak256(abi.encode(topDownMsg.message.from)) - == keccak256(abi.encode(IPCAddress({subnetId: subnetId.getParentSubnet(), rawAddress: funderAddress}))) + keccak256(abi.encode(topDownMsg.message.from)) == + keccak256(abi.encode(IPCAddress({subnetId: subnetId.getParentSubnet(), rawAddress: funderAddress}))) ); } } @@ -2105,14 +2181,14 @@ contract GatewayDeploymentTest is StdInvariant, Test { } function release(uint256 releaseAmount, uint256 crossMsgFee, uint64 epoch) internal { - (,, uint256 feeBefore,,) = gw.bottomUpCheckpoints(epoch); + (, , uint256 feeBefore, , ) = gw.bottomUpCheckpoints(epoch); uint256 expectedNonce = gw.bottomUpNonce() + 1; uint256 expectedCheckpointDataFee = feeBefore + crossMsgFee; gw.release{value: releaseAmount}(); - (,, uint256 fee,,) = gw.bottomUpCheckpoints(epoch); + (, , uint256 fee, , ) = gw.bottomUpCheckpoints(epoch); console.log("fee %d", fee); console.log("expectedCheckpointDataFee: %d", expectedCheckpointDataFee); @@ -2120,11 +2196,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { require(gw.bottomUpNonce() == expectedNonce, "gw.bottomUpNonce() == expectedNonce"); } - function createCheckpoint(address subnetAddress, uint64 blockNumber) - internal - view - returns (BottomUpCheckpoint memory) - { + function createCheckpoint( + address subnetAddress, + uint64 blockNumber + ) internal view returns (BottomUpCheckpoint memory) { SubnetID memory subnetId = gw.getNetworkName().createSubnetId(subnetAddress); BottomUpCheckpoint memory checkpoint = BottomUpCheckpoint({ source: subnetId, @@ -2141,12 +2216,12 @@ contract GatewayDeploymentTest is StdInvariant, Test { function addStake(uint256 stakeAmount, address subnetAddress) internal { uint256 balanceBefore = subnetAddress.balance; - (, uint256 stakedBefore,,,,) = getSubnet(subnetAddress); + (, uint256 stakedBefore, , , , ) = getSubnet(subnetAddress); gw.addStake{value: stakeAmount}(); uint256 balanceAfter = subnetAddress.balance; - (, uint256 stakedAfter,,,,) = getSubnet(subnetAddress); + (, uint256 stakedAfter, , , , ) = getSubnet(subnetAddress); require(balanceAfter == balanceBefore - stakeAmount); require(stakedAfter == stakedBefore + stakeAmount); @@ -2155,8 +2230,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { function registerSubnetGW(uint256 collateral, address subnetAddress, Gateway gateway) internal { gateway.register{value: collateral}(); - (SubnetID memory id, uint256 stake, uint256 topDownNonce,, uint256 circSupply, Status status) = - getSubnetGW(subnetAddress, gateway); + (SubnetID memory id, uint256 stake, uint256 topDownNonce, , uint256 circSupply, Status status) = getSubnetGW( + subnetAddress, + gateway + ); SubnetID memory parentNetwork = gateway.getNetworkName(); @@ -2174,11 +2251,10 @@ contract GatewayDeploymentTest is StdInvariant, Test { registerSubnetGW(collateral, subnetAddress, gw); } - function getSubnetGW(address subnetAddress, Gateway gateway) - internal - view - returns (SubnetID memory, uint256, uint256, uint256, uint256, Status) - { + function getSubnetGW( + address subnetAddress, + Gateway gateway + ) internal view returns (SubnetID memory, uint256, uint256, uint256, uint256, Status) { SubnetID memory subnetId = gateway.getNetworkName().createSubnetId(subnetAddress); ( @@ -2189,16 +2265,15 @@ contract GatewayDeploymentTest is StdInvariant, Test { , uint256 circSupply, SubnetID memory id, + ) = gateway.subnets(subnetId.toHash()); return (id, stake, topDownNonce, appliedBottomUpNonce, circSupply, status); } - function getSubnet(address subnetAddress) - internal - view - returns (SubnetID memory, uint256, uint256, uint256, uint256, Status) - { + function getSubnet( + address subnetAddress + ) internal view returns (SubnetID memory, uint256, uint256, uint256, uint256, Status) { return getSubnetGW(subnetAddress, gw); } } diff --git a/test/StorableMsgHelper.t.sol b/test/StorableMsgHelper.t.sol index f0a300a5e..141e30bdc 100644 --- a/test/StorableMsgHelper.t.sol +++ b/test/StorableMsgHelper.t.sol @@ -10,18 +10,20 @@ contract StorableMsgHelperTest is Test { uint64 private constant ROOTNET_CHAINID = 123; - StorableMsg EMPTY_STORABLE_MESSAGE = StorableMsg({ - from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), - value: 0, - nonce: 0, - method: METHOD_SEND, - params: EMPTY_BYTES - }); + StorableMsg EMPTY_STORABLE_MESSAGE = + StorableMsg({ + from: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + to: IPCAddress({subnetId: SubnetID(0, new address[](0)), rawAddress: address(0)}), + value: 0, + nonce: 0, + method: METHOD_SEND, + params: EMPTY_BYTES + }); function test_ToHash_Works_EmptyMessage() public view { require( - EMPTY_STORABLE_MESSAGE.toHash() == StorableMsgHelper.EMPTY_STORABLE_MESSAGE_HASH, "Hashes should be equal" + EMPTY_STORABLE_MESSAGE.toHash() == StorableMsgHelper.EMPTY_STORABLE_MESSAGE_HASH, + "Hashes should be equal" ); } diff --git a/test/SubnetActor.t.sol b/test/SubnetActor.t.sol index ae329e2eb..61c78d146 100644 --- a/test/SubnetActor.t.sol +++ b/test/SubnetActor.t.sol @@ -106,30 +106,32 @@ contract SubnetActorTest is Test { function test_Deployments_Fail_GatewayCannotBeZero() public { vm.expectRevert(GatewayCannotBeZero.selector); - new SubnetActor(SubnetActor.ConstructParams({ - parentId: SubnetID(ROOTNET_CHAINID, new address[](0)), - name: DEFAULT_NETWORK_NAME, - ipcGatewayAddr: address(0), - consensus: ConsensusType.Mir, - minActivationCollateral: DEFAULT_MIN_VALIDATOR_STAKE, - minValidators: DEFAULT_MIN_VALIDATORS, - bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD, - topDownCheckPeriod: DEFAULT_CHECKPOINT_PERIOD, - majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE, - genesis: EMPTY_BYTES - })); + new SubnetActor( + SubnetActor.ConstructParams({ + parentId: SubnetID(ROOTNET_CHAINID, new address[](0)), + name: DEFAULT_NETWORK_NAME, + ipcGatewayAddr: address(0), + consensus: ConsensusType.Mir, + minActivationCollateral: DEFAULT_MIN_VALIDATOR_STAKE, + minValidators: DEFAULT_MIN_VALIDATORS, + bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD, + topDownCheckPeriod: DEFAULT_CHECKPOINT_PERIOD, + majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE, + genesis: EMPTY_BYTES + }) + ); } function test_Receive_Fail_NotGateway() public { vm.expectRevert(NotGateway.selector); - (bool success,) = payable(address(sa)).call{value: 1}(""); + (bool success, ) = payable(address(sa)).call{value: 1}(""); require(success); } function test_Receive_Works() public { vm.prank(GATEWAY_ADDRESS); vm.deal(GATEWAY_ADDRESS, 1); - (bool success,) = payable(address(sa)).call{value: 1}(""); + (bool success, ) = payable(address(sa)).call{value: 1}(""); require(success); } @@ -357,13 +359,14 @@ contract SubnetActorTest is Test { _assertVote(validator2, checkpoint); vm.expectCall( - GATEWAY_ADDRESS, abi.encodeWithSelector(IGateway(GATEWAY_ADDRESS).commitChildCheck.selector, checkpoint) + GATEWAY_ADDRESS, + abi.encodeWithSelector(IGateway(GATEWAY_ADDRESS).commitChildCheck.selector, checkpoint) ); _assertVote(validator3, checkpoint); - (SubnetID memory source, uint64 epoch, uint256 fee, bytes32 prevHash, bytes memory proof) = - sa.committedCheckpoints(checkpoint.epoch); + (SubnetID memory source, uint64 epoch, uint256 fee, bytes32 prevHash, bytes memory proof) = sa + .committedCheckpoints(checkpoint.epoch); require(sa.prevExecutedCheckpointHash() == checkpoint.toHash()); require(sa.lastVotingExecutedEpoch() == checkpoint.epoch); @@ -425,8 +428,8 @@ contract SubnetActorTest is Test { // vote for checkpoint 4 and trigger execution of checkpoint 3 from the queue _assertVote(validator, checkpoint4); - (SubnetID memory source, uint64 epoch, uint256 fee, bytes32 prevHash, bytes memory proof) = - sa.committedCheckpoints(checkpoint3.epoch); + (SubnetID memory source, uint64 epoch, uint256 fee, bytes32 prevHash, bytes memory proof) = sa + .committedCheckpoints(checkpoint3.epoch); require(sa.lastVotingExecutedEpoch() == checkpoint3.epoch); require(sa.prevExecutedCheckpointHash() == checkpoint3.toHash()); @@ -477,7 +480,10 @@ contract SubnetActorTest is Test { subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: address(this) }), - to: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: address(this)}), + to: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: address(this) + }), value: CROSS_MSG_FEE + 1, nonce: 1, method: METHOD_SEND, @@ -491,7 +497,10 @@ contract SubnetActorTest is Test { subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: address(this) }), - to: IPCAddress({subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), rawAddress: address(this)}), + to: IPCAddress({ + subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), + rawAddress: address(this) + }), value: CROSS_MSG_FEE + 1, nonce: 0, method: METHOD_SEND, @@ -540,7 +549,9 @@ contract SubnetActorTest is Test { // not commited vm.expectCall( - GATEWAY_ADDRESS, abi.encodeWithSelector(IGateway(GATEWAY_ADDRESS).commitChildCheck.selector, checkpoint2), 0 + GATEWAY_ADDRESS, + abi.encodeWithSelector(IGateway(GATEWAY_ADDRESS).commitChildCheck.selector, checkpoint2), + 0 ); vm.prank(validator3); diff --git a/test/SubnetIDHelper.t.sol b/test/SubnetIDHelper.t.sol index 0c75860d4..87fcd4a1e 100644 --- a/test/SubnetIDHelper.t.sol +++ b/test/SubnetIDHelper.t.sol @@ -297,12 +297,12 @@ contract SubnetIDHelperTest is Test { route2[0] = SUBNET_TWO_ADDRESS; require( - SubnetID({root: ROOTNET_CHAINID, route: route}).equals(SubnetID({root: ROOTNET_CHAINID, route: route})) - == true + SubnetID({root: ROOTNET_CHAINID, route: route}).equals(SubnetID({root: ROOTNET_CHAINID, route: route})) == + true ); require( - SubnetID({root: ROOTNET_CHAINID, route: route}).equals(SubnetID({root: ROOTNET_CHAINID, route: route2})) - == false + SubnetID({root: ROOTNET_CHAINID, route: route}).equals(SubnetID({root: ROOTNET_CHAINID, route: route2})) == + false ); }