From 463ee742828f12e78c6cdb4691d4441c883fe6f8 Mon Sep 17 00:00:00 2001 From: Karel Moravec Date: Fri, 11 Oct 2024 17:20:58 +0200 Subject: [PATCH] feat: fix tests --- .../gateway/router/XnetMessagingFacet.sol | 2 +- contracts/contracts/lib/LibGateway.sol | 33 +++++++++++++++ .../test/integration/GatewayDiamond.t.sol | 8 ++-- .../test/integration/L2GatewayDiamond.t.sol | 41 ++++++------------- contracts/test/integration/L2PlusSubnet.t.sol | 27 +++--------- 5 files changed, 56 insertions(+), 55 deletions(-) diff --git a/contracts/contracts/gateway/router/XnetMessagingFacet.sol b/contracts/contracts/gateway/router/XnetMessagingFacet.sol index c7e3c2a7e..ef479558a 100644 --- a/contracts/contracts/gateway/router/XnetMessagingFacet.sol +++ b/contracts/contracts/gateway/router/XnetMessagingFacet.sol @@ -27,6 +27,6 @@ contract XnetMessagingFacet is GatewayActorModifiers { /// @dev It requires the caller to be the system actor. /// @param crossMsgs The array of cross-network messages to be applied. function applyCrossMessages(IpcEnvelope[] calldata crossMsgs) external systemActorOnly { - LibGateway.applyMessages(s.networkName.getParentSubnet(), crossMsgs); + LibGateway.applyTopDownMessages(s.networkName.getParentSubnet(), crossMsgs); } } diff --git a/contracts/contracts/lib/LibGateway.sol b/contracts/contracts/lib/LibGateway.sol index f318bf226..b8f4e28ad 100644 --- a/contracts/contracts/lib/LibGateway.sol +++ b/contracts/contracts/lib/LibGateway.sol @@ -341,6 +341,7 @@ library LibGateway { return ((uint64(blockNumber) / checkPeriod) + 1) * checkPeriod; } + /// @notice applies a cross-net messages coming from some other subnet. /// The forwarder argument determines the previous subnet that submitted the checkpoint triggering the cross-net message execution. /// @param arrivingFrom - the immediate subnet from which this message is arriving @@ -355,6 +356,19 @@ library LibGateway { } } + /// @notice applies a top down messages coming from parent. Reverts if a message is not top-down. + /// @param arrivingFrom - the immediate subnet from which this message is arriving + /// @param crossMsgs - the cross-net messages to apply + function applyTopDownMessages(SubnetID memory arrivingFrom, IpcEnvelope[] memory crossMsgs) internal { + uint256 crossMsgsLength = crossMsgs.length; + for (uint256 i; i < crossMsgsLength; ) { + applyMsg(arrivingFrom, crossMsgs[i], true); + unchecked { + ++i; + } + } + } + /// @notice executes a cross message if its destination is the current network, otherwise adds it to the postbox to be propagated further /// This function assumes that the relevant funds have been already minted or burnt /// when the top-down or bottom-up messages have been queued for execution. @@ -364,6 +378,19 @@ library LibGateway { /// @param arrivingFrom - the immediate subnet from which this message is arriving /// @param crossMsg - the cross message to be executed function applyMsg(SubnetID memory arrivingFrom, IpcEnvelope memory crossMsg) internal { + applyMsg(arrivingFrom, crossMsg, false); + } + + /// @notice executes a cross message if its destination is the current network, otherwise adds it to the postbox to be propagated further + /// This function assumes that the relevant funds have been already minted or burnt + /// when the top-down or bottom-up messages have been queued for execution. + /// This function is not expected to revert. If a controlled failure happens, a new + /// cross-message receipt is propagated for execution to inform the sending contract. + /// `Call` cross-messages also trigger receipts if they are successful. + /// @param arrivingFrom - the immediate subnet from which this message is arriving + /// @param crossMsg - the cross message to be executed + /// @param expectTopDownOnly - whether the message should be top-down only. Reverts if it is not. + function applyMsg(SubnetID memory arrivingFrom, IpcEnvelope memory crossMsg, bool expectTopDownOnly) internal { GatewayActorStorage storage s = LibGatewayActorStorage.appStorage(); if (crossMsg.to.subnetId.isEmpty()) { @@ -377,7 +404,13 @@ library LibGateway { Asset memory supplySource; IPCMsgType applyType = crossMsg.applyType(s.networkName); if (applyType == IPCMsgType.BottomUp) { + if (expectTopDownOnly) { + revert("Expecting top-down messages only"); + } + // Load the subnet this message is coming from. + // It will revert in case the subnet is not found - which in this case makes sense + // This is because non existing child should not send messages. (, Subnet storage subnet) = LibGateway.getSubnet(arrivingFrom); if (subnet.appliedBottomUpNonce != crossMsg.nonce) { diff --git a/contracts/test/integration/GatewayDiamond.t.sol b/contracts/test/integration/GatewayDiamond.t.sol index 0759b98f0..05a0d7a94 100644 --- a/contracts/test/integration/GatewayDiamond.t.sol +++ b/contracts/test/integration/GatewayDiamond.t.sol @@ -31,7 +31,7 @@ import {ERR_GENERAL_CROSS_MSG_DISABLED} from "../../contracts/gateway/GatewayMes import {DiamondCutFacet} from "../../contracts/diamond/DiamondCutFacet.sol"; import {LibDiamond} from "../../contracts/lib/LibDiamond.sol"; import {MerkleTreeHelper} from "../helpers/MerkleTreeHelper.sol"; -import {TestUtils, MockIpcContract} from "../helpers/TestUtils.sol"; +import {TestUtils, MockIpcContract, MockIpcContractPayable} from "../helpers/TestUtils.sol"; import {IntegrationTestBase, SubnetWithNativeTokenMock} from "../IntegrationTestBase.sol"; import {SelectorLibrary} from "../helpers/SelectorLibrary.sol"; import {GatewayFacetsHelper} from "../helpers/GatewayFacetsHelper.sol"; @@ -1169,6 +1169,8 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT function testGatewayDiamond_commitBottomUpCheckpoint_Works_WithMessages() public { address caller = address(saDiamond); + address recipient = address(new MockIpcContractPayable()); + vm.startPrank(caller); vm.deal(caller, DEFAULT_COLLATERAL_AMOUNT + DEFAULT_CROSS_MSG_FEE); registerSubnet(DEFAULT_COLLATERAL_AMOUNT, caller); @@ -1185,7 +1187,7 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT subnetId, FvmAddressHelper.from(address(caller)) ); - (, subnetInfo) = gatewayDiamond.getter().getSubnet(subnetId); + (, subnetInfo) = gatewayDiamond.getter().getSubnet(subnetId); require(subnetInfo.circSupply == DEFAULT_COLLATERAL_AMOUNT, "unexpected circulation supply after funding"); IpcEnvelope[] memory msgs = new IpcEnvelope[](10); @@ -1194,7 +1196,7 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT IPCAddress({subnetId: subnetId, rawAddress: FvmAddressHelper.from(caller)}), IPCAddress({ subnetId: gatewayDiamond.getter().getNetworkName(), - rawAddress: FvmAddressHelper.from(vm.addr(100 + i)) + rawAddress: FvmAddressHelper.from(recipient) }), amount, i diff --git a/contracts/test/integration/L2GatewayDiamond.t.sol b/contracts/test/integration/L2GatewayDiamond.t.sol index a1806af88..0075954b9 100644 --- a/contracts/test/integration/L2GatewayDiamond.t.sol +++ b/contracts/test/integration/L2GatewayDiamond.t.sol @@ -6,7 +6,8 @@ import "../../contracts/errors/IPCErrors.sol"; import {EMPTY_BYTES, METHOD_SEND} from "../../contracts/constants/Constants.sol"; import {IpcEnvelope} from "../../contracts/structs/CrossNet.sol"; import {FvmAddress} from "../../contracts/structs/FvmAddress.sol"; -import {SubnetID, Subnet, IPCAddress, Validator} from "../../contracts/structs/Subnet.sol"; +import {SubnetID, Subnet, IPCAddress, Validator, Asset, AssetKind} from "../../contracts/structs/Subnet.sol"; +import {AssetHelper} from "../../contracts/lib/AssetHelper.sol"; import {SubnetIDHelper} from "../../contracts/lib/SubnetIDHelper.sol"; import {FvmAddressHelper} from "../../contracts/lib/FvmAddressHelper.sol"; import {CrossMsgHelper} from "../../contracts/lib/CrossMsgHelper.sol"; @@ -29,6 +30,7 @@ contract L2GatewayActorDiamondTest is Test, L2GatewayActorDiamond { using SubnetIDHelper for SubnetID; using CrossMsgHelper for IpcEnvelope; using GatewayFacetsHelper for GatewayDiamond; + using AssetHelper for Asset; function testGatewayDiamond_CommitParentFinality_BigNumberOfMessages() public { uint256 n = 2000; @@ -65,38 +67,15 @@ contract L2GatewayActorDiamondTest is Test, L2GatewayActorDiamond { vm.stopPrank(); } - function testGatewayDiamond_Propagate_Works_WithFeeRemainderNew() external { - if (!FEATURE_MULTILEVEL_CROSSMSG) { - // skip - return; - } - (, address[] memory validators) = setupValidators(); - address caller = validators[0]; - - bytes32 postboxId = setupWhiteListMethod(caller); - + function testGatewayDiamond_Propagate_Works() external { + address caller = vm.addr(100); vm.deal(caller, 1 ether); - vm.expectCall(caller, 1 ether, new bytes(0), 1); - vm.prank(caller); - gatewayDiamond.messenger().propagatePostboxMessage{value: 1 ether}(postboxId); - - require(caller.balance == 1 ether, "unexpected balance"); - } - - function testGatewayDiamond_Propagate_Works_NoFeeReminder() external { - if (!FEATURE_MULTILEVEL_CROSSMSG) { - // skip - return; - } - (, address[] memory validators) = setupValidators(); - address caller = validators[0]; - bytes32 postboxId = setupWhiteListMethod(caller); vm.prank(caller); - vm.expectCall(caller, 0, EMPTY_BYTES, 0); - gatewayDiamond.messenger().propagatePostboxMessage{value: 0}(postboxId); + vm.expectCall(caller, 1 ether, EMPTY_BYTES, 0); + gatewayDiamond.messenger().propagatePostboxMessage{value: 1 ether}(postboxId); require(caller.balance == 0, "unexpected balance"); } @@ -105,7 +84,7 @@ contract L2GatewayActorDiamondTest is Test, L2GatewayActorDiamond { IpcEnvelope memory crossMsg = TestUtils.newXnetCallMsg( IPCAddress({ - subnetId: gatewayDiamond.getter().getNetworkName().createSubnetId(caller), + subnetId: gatewayDiamond.getter().getNetworkName().getParentSubnet(), rawAddress: FvmAddressHelper.from(caller) }), IPCAddress({ @@ -125,4 +104,8 @@ contract L2GatewayActorDiamondTest is Test, L2GatewayActorDiamond { } function callback() public view {} + + function collateralSource() external view returns (Asset memory supply) { + return AssetHelper.native(); + } } diff --git a/contracts/test/integration/L2PlusSubnet.t.sol b/contracts/test/integration/L2PlusSubnet.t.sol index ba3ffb513..ea10cab87 100644 --- a/contracts/test/integration/L2PlusSubnet.t.sol +++ b/contracts/test/integration/L2PlusSubnet.t.sol @@ -3,46 +3,34 @@ pragma solidity ^0.8.23; import "forge-std/Test.sol"; import "../../contracts/errors/IPCErrors.sol"; -import {EMPTY_BYTES, METHOD_SEND} from "../../contracts/constants/Constants.sol"; +import {EMPTY_BYTES} from "../../contracts/constants/Constants.sol"; import {IpcEnvelope, BottomUpMsgBatch, BottomUpCheckpoint, ParentFinality, IpcMsgKind, OutcomeType} from "../../contracts/structs/CrossNet.sol"; -import {FvmAddress} from "../../contracts/structs/FvmAddress.sol"; import {SubnetID, Subnet, IPCAddress, Validator} from "../../contracts/structs/Subnet.sol"; import {SubnetIDHelper} from "../../contracts/lib/SubnetIDHelper.sol"; import {AssetHelper} from "../../contracts/lib/AssetHelper.sol"; import {Asset, AssetKind} from "../../contracts/structs/Subnet.sol"; import {FvmAddressHelper} from "../../contracts/lib/FvmAddressHelper.sol"; import {CrossMsgHelper} from "../../contracts/lib/CrossMsgHelper.sol"; -import {GatewayDiamond, FEATURE_MULTILEVEL_CROSSMSG} from "../../contracts/GatewayDiamond.sol"; +import {GatewayDiamond} from "../../contracts/GatewayDiamond.sol"; import {SubnetActorDiamond} from "../../contracts/SubnetActorDiamond.sol"; -import {SubnetActorGetterFacet} from "../../contracts/subnet/SubnetActorGetterFacet.sol"; import {SubnetActorManagerFacet} from "../../contracts/subnet/SubnetActorManagerFacet.sol"; import {SubnetActorCheckpointingFacet} from "../../contracts/subnet/SubnetActorCheckpointingFacet.sol"; import {GatewayGetterFacet} from "../../contracts/gateway/GatewayGetterFacet.sol"; -import {GatewayManagerFacet} from "../../contracts/gateway/GatewayManagerFacet.sol"; import {LibGateway} from "../../contracts/lib/LibGateway.sol"; import {TopDownFinalityFacet} from "../../contracts/gateway/router/TopDownFinalityFacet.sol"; import {CheckpointingFacet} from "../../contracts/gateway/router/CheckpointingFacet.sol"; import {XnetMessagingFacet} from "../../contracts/gateway/router/XnetMessagingFacet.sol"; import {DiamondCutFacet} from "../../contracts/diamond/DiamondCutFacet.sol"; import {GatewayMessengerFacet} from "../../contracts/gateway/GatewayMessengerFacet.sol"; -import {DiamondLoupeFacet} from "../../contracts/diamond/DiamondLoupeFacet.sol"; -import {DiamondCutFacet} from "../../contracts/diamond/DiamondCutFacet.sol"; import {IntegrationTestBase, RootSubnetDefinition, TestSubnetDefinition} from "../IntegrationTestBase.sol"; -import {L2GatewayActorDiamond, L1GatewayActorDiamond} from "../IntegrationTestPresets.sol"; -import {TestUtils, MockIpcContract, MockIpcContractPayable, MockIpcContractResult, MockIpcContractRevert, MockIpcContractFallback} from "../helpers/TestUtils.sol"; +import {TestUtils, MockIpcContract, MockIpcContractPayable, MockIpcContractResult} from "../helpers/TestUtils.sol"; import {FilAddress} from "fevmate/contracts/utils/FilAddress.sol"; import {MerkleTreeHelper} from "../helpers/MerkleTreeHelper.sol"; +import {GatewayFacetsHelper} from "../helpers/GatewayFacetsHelper.sol"; +import {SubnetActorFacetsHelper} from "../helpers/SubnetActorFacetsHelper.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {ERC20PresetFixedSupply} from "../helpers/ERC20PresetFixedSupply.sol"; -import {ERC20Deflationary} from "../helpers/ERC20Deflationary.sol"; -import {ERC20Inflationary} from "../helpers/ERC20Inflationary.sol"; -import {ERC20Nil} from "../helpers/ERC20Nil.sol"; - -import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; - -import {GatewayFacetsHelper} from "../helpers/GatewayFacetsHelper.sol"; -import {SubnetActorFacetsHelper} from "../helpers/SubnetActorFacetsHelper.sol"; import "forge-std/console.sol"; @@ -763,9 +751,4 @@ contract L2PlusSubnetTest is Test, IntegrationTestBase { console.log("native L3-%d subnet actor: %s", i, (nativeL3Subnets[i].subnetActorAddr)); } } - - function printEnvelope(IpcEnvelope memory envelope) internal view { - console.log("from %s:", envelope.from.subnetId.toString()); - console.log("to %s:", envelope.to.subnetId.toString()); - } }