Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

Commit

Permalink
Add skeleton for GatewayActor invariants (#413)
Browse files Browse the repository at this point in the history
This PR establishes a skeleton for future invariant tests for
GatewayActor.
The main idea is to define all basic properties of the gatewayActor and
be able to apply them to many different Gateway instances with different
configurations.
  • Loading branch information
dnkolegov authored Dec 22, 2023
1 parent a3713fe commit f84604c
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 65 deletions.
27 changes: 13 additions & 14 deletions test/IntegrationTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity 0.8.19;

import "forge-std/Test.sol";
import "forge-std/StdInvariant.sol";
import "../src/errors/IPCErrors.sol";

import {EMPTY_BYTES, METHOD_SEND} from "../src/constants/Constants.sol";
Expand Down Expand Up @@ -124,19 +123,6 @@ contract TestGatewayActor is Test, TestParams {
gwCutterSelectors = SelectorLibrary.resolveSelectors("DiamondCutFacet");
gwLoupeSelectors = SelectorLibrary.resolveSelectors("DiamondLoupeFacet");
}

function defaultGatewayParams() internal pure virtual returns (GatewayDiamond.ConstructorParams memory) {
GatewayDiamond.ConstructorParams memory params = GatewayDiamond.ConstructorParams({
networkName: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}),
bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD,
msgFee: DEFAULT_CROSS_MSG_FEE,
majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE,
genesisValidators: new Validator[](0),
activeValidatorsLimit: DEFAULT_ACTIVE_VALIDATORS_LIMIT
});

return params;
}
}

contract TestSubnetActor is Test, TestParams {
Expand Down Expand Up @@ -240,6 +226,19 @@ contract IntegrationTestBase is Test, TestParams, TestRegistry, TestSubnetActor,
addValidator(TOPDOWN_VALIDATOR_1, 100);
}

function defaultGatewayParams() internal pure virtual returns (GatewayDiamond.ConstructorParams memory) {
GatewayDiamond.ConstructorParams memory params = GatewayDiamond.ConstructorParams({
networkName: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}),
bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD,
msgFee: DEFAULT_CROSS_MSG_FEE,
majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE,
genesisValidators: new Validator[](0),
activeValidatorsLimit: DEFAULT_ACTIVE_VALIDATORS_LIMIT
});

return params;
}

function createGatewayDiamond(GatewayDiamond.ConstructorParams memory params) public returns (GatewayDiamond) {
CheckpointingFacet checkpointingFacet = new CheckpointingFacet();
XnetMessagingFacet xnetMessagingFacet = new XnetMessagingFacet();
Expand Down
107 changes: 107 additions & 0 deletions test/IntegrationTestPresets.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.19;

import {SubnetID, Subnet, IPCAddress, Validator} from "../src/structs/Subnet.sol";
import {DiamondCutFacet} from "../src/diamond/DiamondCutFacet.sol";
import {DiamondLoupeFacet} from "../src/diamond/DiamondLoupeFacet.sol";
import {GatewayDiamond} from "../src/GatewayDiamond.sol";
import {GatewayGetterFacet} from "../src/gateway/GatewayGetterFacet.sol";
import {GatewayManagerFacet} from "../src/gateway/GatewayManagerFacet.sol";
import {GatewayMessengerFacet} from "../src/gateway/GatewayMessengerFacet.sol";
import {XnetMessagingFacet} from "../src/gateway/router/XnetMessagingFacet.sol";
import {IntegrationTestBase} from "./IntegrationTestBase.sol";

contract L1GatewayActorDiamond is IntegrationTestBase {
function setUp() public virtual override {
GatewayDiamond.ConstructorParams memory gwConstructorParams = defaultGatewayParams();
gatewayDiamond = createGatewayDiamond(gwConstructorParams);

gwGetter = GatewayGetterFacet(address(gatewayDiamond));
gwManager = GatewayManagerFacet(address(gatewayDiamond));
gwXnetMessagingFacet = XnetMessagingFacet(address(gatewayDiamond));
gwMessenger = GatewayMessengerFacet(address(gatewayDiamond));
gwLouper = DiamondLoupeFacet(address(gatewayDiamond));
gwCutter = DiamondCutFacet(address(gatewayDiamond));
}

function defaultGatewayParams() internal pure override returns (GatewayDiamond.ConstructorParams memory) {
address[] memory path = new address[](1);
path[0] = CHILD_NETWORK_ADDRESS;

GatewayDiamond.ConstructorParams memory params = GatewayDiamond.ConstructorParams({
networkName: SubnetID({root: ROOTNET_CHAINID, route: path}),
bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD,
msgFee: DEFAULT_CROSS_MSG_FEE,
majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE,
genesisValidators: new Validator[](0),
activeValidatorsLimit: DEFAULT_ACTIVE_VALIDATORS_LIMIT
});

return params;
}
}

contract L2GatewayActorDiamond is IntegrationTestBase {
function setUp() public virtual override {
GatewayDiamond.ConstructorParams memory gwConstructorParams = defaultGatewayParams();
gatewayDiamond = createGatewayDiamond(gwConstructorParams);

gwGetter = GatewayGetterFacet(address(gatewayDiamond));
gwManager = GatewayManagerFacet(address(gatewayDiamond));
gwXnetMessagingFacet = XnetMessagingFacet(address(gatewayDiamond));
gwMessenger = GatewayMessengerFacet(address(gatewayDiamond));
gwLouper = DiamondLoupeFacet(address(gatewayDiamond));
gwCutter = DiamondCutFacet(address(gatewayDiamond));
}

function defaultGatewayParams() internal pure override returns (GatewayDiamond.ConstructorParams memory) {
address[] memory path = new address[](2);
path[0] = CHILD_NETWORK_ADDRESS;
path[1] = CHILD_NETWORK_ADDRESS_2;

GatewayDiamond.ConstructorParams memory params = GatewayDiamond.ConstructorParams({
networkName: SubnetID({root: ROOTNET_CHAINID, route: path}),
bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD,
msgFee: DEFAULT_CROSS_MSG_FEE,
majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE,
genesisValidators: new Validator[](0),
activeValidatorsLimit: DEFAULT_ACTIVE_VALIDATORS_LIMIT
});

return params;
}
}

contract L3GatewayActorDiamond is IntegrationTestBase {
address constant CHILD_NETWORK_ADDRESS_3 = address(31);

function setUp() public virtual override {
GatewayDiamond.ConstructorParams memory gwConstructorParams = defaultGatewayParams();
gatewayDiamond = createGatewayDiamond(gwConstructorParams);

gwGetter = GatewayGetterFacet(address(gatewayDiamond));
gwManager = GatewayManagerFacet(address(gatewayDiamond));
gwXnetMessagingFacet = XnetMessagingFacet(address(gatewayDiamond));
gwMessenger = GatewayMessengerFacet(address(gatewayDiamond));
gwLouper = DiamondLoupeFacet(address(gatewayDiamond));
gwCutter = DiamondCutFacet(address(gatewayDiamond));
}

function defaultGatewayParams() internal pure override returns (GatewayDiamond.ConstructorParams memory) {
address[] memory path = new address[](3);
path[0] = CHILD_NETWORK_ADDRESS;
path[1] = CHILD_NETWORK_ADDRESS_2;
path[1] = CHILD_NETWORK_ADDRESS_2;

GatewayDiamond.ConstructorParams memory params = GatewayDiamond.ConstructorParams({
networkName: SubnetID({root: ROOTNET_CHAINID, route: path}),
bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD,
msgFee: DEFAULT_CROSS_MSG_FEE,
majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE,
genesisValidators: new Validator[](0),
activeValidatorsLimit: DEFAULT_ACTIVE_VALIDATORS_LIMIT
});

return params;
}
}
20 changes: 3 additions & 17 deletions test/integration/GatewayDiamondToken.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,20 @@ pragma solidity 0.8.19;
import "forge-std/Test.sol";

import "../../src/errors/IPCErrors.sol";
import {NumberContractFacetSeven} from "../helpers/NumberContractFacetSeven.sol";
import {NumberContractFacetEight} from "../helpers/NumberContractFacetEight.sol";
import {EMPTY_BYTES, METHOD_SEND, EMPTY_HASH} from "../../src/constants/Constants.sol";
import {IERC165} from "../../src/interfaces/IERC165.sol";
import {IDiamond} from "../../src/interfaces/IDiamond.sol";
import {IDiamondLoupe} from "../../src/interfaces/IDiamondLoupe.sol";
import {IDiamondCut} from "../../src/interfaces/IDiamondCut.sol";
import {CrossMsg, BottomUpMsgBatch, BottomUpCheckpoint, StorableMsg, ParentFinality} from "../../src/structs/CrossNet.sol";
import {CrossMsg, BottomUpMsgBatch, StorableMsg} from "../../src/structs/CrossNet.sol";
import {FvmAddress} from "../../src/structs/FvmAddress.sol";
import {SubnetID, Subnet, SupplySource, SupplyKind, IPCAddress, Membership, Validator, StakingChange, StakingChangeRequest, StakingOperation} from "../../src/structs/Subnet.sol";
import {SubnetID, Subnet, SupplySource, SupplyKind, Validator} from "../../src/structs/Subnet.sol";
import {SubnetIDHelper} from "../../src/lib/SubnetIDHelper.sol";
import {FvmAddressHelper} from "../../src/lib/FvmAddressHelper.sol";
import {CrossMsgHelper} from "../../src/lib/CrossMsgHelper.sol";
import {SupplySourceHelper} from "../../src/lib/SupplySourceHelper.sol";
import {StorableMsgHelper} from "../../src/lib/StorableMsgHelper.sol";
import {FilAddress} from "fevmate/utils/FilAddress.sol";
import {GatewayDiamond, FunctionNotFound} from "../../src/GatewayDiamond.sol";
import {SubnetActorDiamond} from "../../src/SubnetActorDiamond.sol";
import {GatewayGetterFacet} from "../../src/gateway/GatewayGetterFacet.sol";
import {GatewayManagerFacet} from "../../src/gateway/GatewayManagerFacet.sol";
import {DiamondCutFacet} from "../../src/diamond/DiamondCutFacet.sol";
import {LibDiamond} from "../../src/lib/LibDiamond.sol";
import {GatewayDiamond} from "../../src/GatewayDiamond.sol";
import {LibGateway} from "../../src/lib/LibGateway.sol";
import {MerkleTreeHelper} from "../helpers/MerkleTreeHelper.sol";
import {TestUtils} from "../helpers/TestUtils.sol";
import {IntegrationTestBase} from "../IntegrationTestBase.sol";

import {SubnetActorDiamond} from "../../src/SubnetActorDiamond.sol";
import {GatewayGetterFacet} from "../../src/gateway/GatewayGetterFacet.sol";
import {GatewayMessengerFacet} from "../../src/gateway/GatewayMessengerFacet.sol";
Expand All @@ -39,7 +26,6 @@ import {SubnetActorManagerFacet} from "../../src/subnet/SubnetActorManagerFacet.
import {SubnetActorGetterFacet} from "../../src/subnet/SubnetActorGetterFacet.sol";
import {DiamondLoupeFacet} from "../../src/diamond/DiamondLoupeFacet.sol";
import {DiamondCutFacet} from "../../src/diamond/DiamondCutFacet.sol";
import {LibDiamond} from "../../src/lib/LibDiamond.sol";

import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import {ERC20PresetFixedSupply} from "../helpers/ERC20PresetFixedSupply.sol";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,13 @@ import {GatewayMessengerFacet} from "../../src/gateway/GatewayMessengerFacet.sol
import {DiamondLoupeFacet} from "../../src/diamond/DiamondLoupeFacet.sol";
import {DiamondCutFacet} from "../../src/diamond/DiamondCutFacet.sol";
import {IntegrationTestBase} from "../IntegrationTestBase.sol";
import {L2GatewayActorDiamond} from "../IntegrationTestPresets.sol";
import {FilAddress} from "fevmate/utils/FilAddress.sol";

contract GatewayL2ActorDiamondTest is Test, IntegrationTestBase {
contract L2GatewayActorDiamondTest is Test, L2GatewayActorDiamond {
using SubnetIDHelper for SubnetID;
using CrossMsgHelper for CrossMsg;

function setUp() public override {
address[] memory path2 = new address[](2);
path2[0] = CHILD_NETWORK_ADDRESS;
path2[1] = CHILD_NETWORK_ADDRESS_2;

GatewayDiamond.ConstructorParams memory gwConstructorParams = defaultGatewayParams();
gatewayDiamond = createGatewayDiamond(gwConstructorParams);

gwGetter = GatewayGetterFacet(address(gatewayDiamond));
gwManager = GatewayManagerFacet(address(gatewayDiamond));
gwXnetMessagingFacet = XnetMessagingFacet(address(gatewayDiamond));
gwMessenger = GatewayMessengerFacet(address(gatewayDiamond));
gwLouper = DiamondLoupeFacet(address(gatewayDiamond));
gwCutter = DiamondCutFacet(address(gatewayDiamond));
}

function defaultGatewayParams() internal pure override returns (GatewayDiamond.ConstructorParams memory) {
address[] memory path2 = new address[](2);
path2[0] = CHILD_NETWORK_ADDRESS;
path2[1] = CHILD_NETWORK_ADDRESS_2;

GatewayDiamond.ConstructorParams memory params = GatewayDiamond.ConstructorParams({
networkName: SubnetID({root: ROOTNET_CHAINID, route: path2}),
bottomUpCheckPeriod: DEFAULT_CHECKPOINT_PERIOD,
msgFee: DEFAULT_CROSS_MSG_FEE,
majorityPercentage: DEFAULT_MAJORITY_PERCENTAGE,
genesisValidators: new Validator[](0),
activeValidatorsLimit: DEFAULT_ACTIVE_VALIDATORS_LIMIT
});

return params;
}

function testGatewayDiamond_CommitParentFinality_BigNumberOfMessages() public {
uint256 n = 2000;
FvmAddress[] memory validators = new FvmAddress[](1);
Expand Down
47 changes: 47 additions & 0 deletions test/invariants/GatewayActorInvariantTests.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.19;

import {StdInvariant} from "forge-std/StdInvariant.sol";
import {GatewayDiamond} from "../../src/GatewayDiamond.sol";
import {L1GatewayActorDiamond, L2GatewayActorDiamond, L3GatewayActorDiamond} from "../IntegrationTestPresets.sol";
import {GatewayActorHandler} from "./handlers/GatewayActorHandler.sol";
import {GatewayActorBasicProperties} from "./GatewayActorProperties.sol";

contract GatewayActorInvariantTests is StdInvariant, L1GatewayActorDiamond, GatewayActorBasicProperties {
GatewayActorHandler private gatewayActorHandler;

function setUp() public override {
L1GatewayActorDiamond.setUp();
gatewayActorHandler = new GatewayActorHandler(gatewayDiamond);
targetContract(address(gatewayActorHandler));

// assert specific properties of the infrastructure.
assertEq(gwGetter.getNetworkName().route.length, 1);
}
}

contract L2GatewayActorInvariantTests is L2GatewayActorDiamond, GatewayActorBasicProperties {
GatewayActorHandler private gatewayActorHandler;

function setUp() public override {
L2GatewayActorDiamond.setUp();
gatewayActorHandler = new GatewayActorHandler(gatewayDiamond);
targetContract(address(gatewayActorHandler));

// assert specific properties of the infrastructure.
assertEq(gwGetter.getNetworkName().route.length, 2);
}
}

contract L3GatewayActorInvariantTests is L3GatewayActorDiamond, GatewayActorBasicProperties {
GatewayActorHandler private gatewayActorHandler;

function setUp() public override {
L3GatewayActorDiamond.setUp();
gatewayActorHandler = new GatewayActorHandler(gatewayDiamond);
targetContract(address(gatewayActorHandler));

// assert specific properties of the infrastructure.
assertEq(gwGetter.getNetworkName().route.length, 3);
}
}
17 changes: 17 additions & 0 deletions test/invariants/GatewayActorProperties.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.19;

import {StdAssertions} from "forge-std/StdAssertions.sol";
import {GatewayGetterFacet} from "../../src/gateway/GatewayGetterFacet.sol";
import {IntegrationTestBase, TestGatewayActor} from "../IntegrationTestBase.sol";

/// @title GatewayActor properties.
/// @dev It is suggested that all properties are defined here.
/// To check that a concrete GatewayActor instance holds the properties that target contract should inherit from this contract.
/// This contract must be abstract.
abstract contract GatewayActorBasicProperties is StdAssertions, TestGatewayActor {
/// @notice The number of subnets is consistent within GatewayActor mechanisms.
function invariant_GA_01_consistent_subnet_number() public virtual {
assertEq(gwGetter.totalSubnets(), gwGetter.listSubnets().length, "the number of subnets is not consistent");
}
}
41 changes: 41 additions & 0 deletions test/invariants/handlers/GatewayActorHandler.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity 0.8.19;

import "forge-std/StdUtils.sol";
import "forge-std/StdCheats.sol";
import {CommonBase} from "forge-std/Base.sol";
import {GatewayDiamond} from "../../../src/GatewayDiamond.sol";
import {BottomUpRouterFacet} from "../../../src/gateway/router/BottomUpRouterFacet.sol";
import {GatewayManagerFacet} from "../../../src/gateway/GatewayManagerFacet.sol";
import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";

uint256 constant ETH_SUPPLY = 129_590_000 ether;

contract GatewayActorHandler is CommonBase, StdCheats, StdUtils {
GatewayManagerFacet managerFacet;

uint256 private constant DEFAULT_MIN_VALIDATOR_STAKE = 10 ether;

constructor(GatewayDiamond _gw) {
managerFacet = GatewayManagerFacet(address(_gw));

deal(address(this), ETH_SUPPLY);
}

function register(uint256 amount) public {
amount = bound(amount, 0, 3 * DEFAULT_MIN_VALIDATOR_STAKE);
managerFacet.register(amount);
}

function stake(uint256 amount) public {
amount = bound(amount, 0, 3 * DEFAULT_MIN_VALIDATOR_STAKE);
managerFacet.addStake{value: amount}();
}

function _pay(address to, uint256 amount) internal {
(bool s, ) = to.call{value: amount}("");
require(s, "pay() failed");
}

receive() external payable {}
}

0 comments on commit f84604c

Please sign in to comment.