Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cross docs #1251

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6343017
feat: add simple tests
karlem Sep 25, 2024
3c18e12
feat: happy path with propagateAll
karlem Sep 26, 2024
a95fa93
feat: add more tests
karlem Oct 1, 2024
39b1a1c
feat: check for proper path propagation
karlem Oct 1, 2024
8fb277f
feat: added result paths to test
karlem Oct 2, 2024
e31475d
feat: add extra test and emits
karlem Oct 7, 2024
bb2b83c
feat: add missing actor tests + refactor
karlem Oct 8, 2024
0cb82a9
feat: move validation
karlem Oct 9, 2024
d2bfdd9
feat: commit cross messages does not revert & fix tests
karlem Oct 10, 2024
488a921
feat: remove logs
karlem Oct 10, 2024
b3c962a
feat: fix tests
karlem Oct 11, 2024
9287fe4
feat: fmt
karlem Oct 11, 2024
9d01bf8
feat: send across mixed token supplies
karlem Oct 11, 2024
142d4d8
feat: propagate top down automatically
karlem Oct 11, 2024
f677ef1
feat: fmt & lint
karlem Oct 11, 2024
807c030
feat: add extra check
karlem Oct 11, 2024
471e059
feat: fix test & lint
karlem Oct 14, 2024
e923695
feat: fix comments
karlem Oct 16, 2024
7b4d142
feat: fix comments
karlem Oct 24, 2024
9c98fe8
feat: change error message
karlem Oct 24, 2024
ffab27e
feat: make sure ID is the same cross network & fix down func
karlem Oct 28, 2024
a3b7fd0
feat: update from comments
karlem Oct 28, 2024
7e18939
feat: do not move funds with call kind
karlem Nov 27, 2024
9df5c8b
feat: rebase fixes
karlem Nov 27, 2024
5aff1b4
feat: fmt
karlem Nov 27, 2024
1f2ef32
feat: storage layout
karlem Nov 27, 2024
31b7766
feat: receipt - encode with selector
karlem Dec 4, 2024
0259a0e
feat: fix nonce issue and add tests
karlem Dec 5, 2024
de3e6b1
feat: linbt
karlem Dec 5, 2024
021ea53
feat: disable transfers for Call messages
karlem Dec 5, 2024
469c7bd
feat(node): support l2 utils (#1219)
cryptoAtwill Dec 6, 2024
b9b0dcb
feat(node): support l2 plus value transfer (#1240)
cryptoAtwill Dec 31, 2024
fab6ae5
chore(contracts): L3+ remove unnecessary `CrossMessageValidationOutco…
raulk Jan 2, 2025
73e7ef8
feat: consistent non clashing tracing id
karlem Jan 9, 2025
490ce5e
fix: test
karlem Jan 9, 2025
edae481
feat: add original nonce to fendermint
karlem Jan 9, 2025
f37b285
fix: build
karlem Jan 9, 2025
1a84b42
fix: rename nonce to local nonce
karlem Jan 10, 2025
b12e566
fix: formatter
karlem Jan 10, 2025
c387cdc
fix: build, test, storage
karlem Jan 10, 2025
22e5009
fix: storage layoyt
karlem Jan 10, 2025
6b2bdcf
feat: add cross docs
karlem Jan 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
478 changes: 284 additions & 194 deletions contracts/.storage-layouts/GatewayActorModifiers.json

Large diffs are not rendered by default.

478 changes: 284 additions & 194 deletions contracts/.storage-layouts/GatewayDiamond.json

Large diffs are not rendered by default.

386 changes: 234 additions & 152 deletions contracts/.storage-layouts/SubnetActorDiamond.json

Large diffs are not rendered by default.

386 changes: 234 additions & 152 deletions contracts/.storage-layouts/SubnetActorModifiers.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions contracts/contracts/GatewayDiamond.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {BATCH_PERIOD, MAX_MSGS_PER_BATCH} from "./structs/CrossNet.sol";

error FunctionNotFound(bytes4 _functionSelector);

bool constant FEATURE_MULTILEVEL_CROSSMSG = false;
bool constant FEATURE_MULTILEVEL_CROSSMSG = true;
bool constant FEATURE_GENERAL_PUPRPOSE_CROSSMSG = true;
uint8 constant FEATURE_SUBNET_DEPTH = 2;
uint8 constant FEATURE_SUBNET_DEPTH = 10;

contract GatewayDiamond {
GatewayActorStorage internal s;
Expand Down
6 changes: 4 additions & 2 deletions contracts/contracts/errors/IPCErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ error AlreadyRegisteredSubnet();
error AlreadyInSet();
error CannotConfirmFutureChanges();
error CannotReleaseZero();
error CannotSendCrossMsgToItself();
error CheckpointAlreadyExists();
error BatchAlreadyExists();
error MaxMsgsPerBatchExceeded();
Expand Down Expand Up @@ -90,7 +89,10 @@ enum InvalidXnetMessageReason {
DstSubnet,
Nonce,
Value,
Kind
Kind,
ReflexiveSend,
NoRoute,
IncompatibleSupplySource
}

string constant ERR_PERMISSIONED_AND_BOOTSTRAPPED = "Method not allowed if permissioned is enabled and subnet bootstrapped";
Expand Down
72 changes: 72 additions & 0 deletions contracts/contracts/examples/CrossMessengerCaller.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.23;

import {FvmAddress} from "../structs/FvmAddress.sol";
import {SubnetID, IPCAddress} from "../structs/Subnet.sol";
import {IpcEnvelope, IpcMsgKind, CallMsg, ResultMsg} from "../structs/CrossNet.sol";
import {IGateway} from "../interfaces/IGateway.sol";
import {SubnetIDHelper} from "../lib/SubnetIDHelper.sol";
import {FvmAddressHelper} from "../lib/FvmAddressHelper.sol";
import {EMPTY_BYTES, METHOD_SEND} from "../constants/Constants.sol";
import {IpcExchange} from "../../sdk/IpcContract.sol";

interface ISubnetGetter {
function ipcGatewayAddr() external view returns (address);
function getParent() external view returns (SubnetID memory);
}

/// This is a simple example contract to invoke cross messages between subnets from different levels
contract CrossMessengerCaller is IpcExchange {
event CallReceived(IPCAddress from, CallMsg msg);
event ResultReceived(IpcEnvelope original, ResultMsg result);

uint256 public callsReceived;
uint256 public resultsReceived;

constructor(address gatewayAddr_) IpcExchange(gatewayAddr_) {
callsReceived = 0;
resultsReceived = 0;
}

function _handleIpcCall(
IpcEnvelope memory envelope,
CallMsg memory callMsg
) internal override returns (bytes memory) {
emit CallReceived(envelope.from, callMsg);
callsReceived += 1;
return EMPTY_BYTES;
}

function _handleIpcResult(
IpcEnvelope storage original,
IpcEnvelope memory,
ResultMsg memory resultMsg
) internal override {
resultsReceived += 1;
emit ResultReceived(original, resultMsg);
}

/// @dev Invoke a cross net send fund message from the current subnet to the target subnet
function invokeSendMessage(SubnetID calldata targetSubnet, address recipient, uint256 value) external {
IPCAddress memory to = IPCAddress({subnetId: targetSubnet, rawAddress: FvmAddressHelper.from(recipient)});
CallMsg memory message = CallMsg({method: abi.encodePacked(METHOD_SEND), params: EMPTY_BYTES});
invokeCrossMessage(to, message, value);
}

function invokeCrossMessage(IPCAddress memory to, CallMsg memory callMsg, uint256 value) internal {
// "sendContractXnetMessage" will handle the `from`
IPCAddress memory from;

IpcEnvelope memory envelope = IpcEnvelope({
kind: IpcMsgKind.Call,
from: from,
to: to,
value: value,
message: abi.encode(callMsg),
originalNonce: 0,
localNonce: 0
});

IGateway(gatewayAddr).sendContractXnetMessage(envelope);
}
}
4 changes: 4 additions & 0 deletions contracts/contracts/gateway/GatewayGetterFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ contract GatewayGetterFacet {
return (s.postbox[id]);
}

function postboxMsgs() external view returns (bytes32[] memory) {
return (s.postboxKeys.values());
}

/// @notice Returns the majority percentage required for certain consensus or decision-making processes.
function majorityPercentage() external view returns (uint64) {
return s.majorityPercentage;
Expand Down
8 changes: 4 additions & 4 deletions contracts/contracts/gateway/GatewayManagerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ contract GatewayManagerFacet is GatewayActorModifiers, ReentrancyGuard {
revert InvalidXnetMessage(InvalidXnetMessageReason.Value);
}
// slither-disable-next-line unused-return
(bool registered, ) = LibGateway.getSubnet(subnetId);
(bool registered, Subnet storage subnet) = LibGateway.getSubnet(subnetId);
if (!registered) {
revert NotRegisteredSubnet();
}
Expand All @@ -158,7 +158,7 @@ contract GatewayManagerFacet is GatewayActorModifiers, ReentrancyGuard {
});

// commit top-down message.
LibGateway.commitTopDownMsg(crossMsg);
LibGateway.commitTopDownMsg(subnet, crossMsg);
}

/// @notice Sends funds to a specified subnet receiver using ERC20 tokens.
Expand All @@ -174,7 +174,7 @@ contract GatewayManagerFacet is GatewayActorModifiers, ReentrancyGuard {
revert InvalidXnetMessage(InvalidXnetMessageReason.Value);
}
// slither-disable-next-line unused-return
(bool registered, ) = LibGateway.getSubnet(subnetId);
(bool registered, Subnet storage subnet) = LibGateway.getSubnet(subnetId);
if (!registered) {
revert NotRegisteredSubnet();
}
Expand All @@ -199,7 +199,7 @@ contract GatewayManagerFacet is GatewayActorModifiers, ReentrancyGuard {
});

// Commit top-down message.
LibGateway.commitTopDownMsg(crossMsg);
LibGateway.commitTopDownMsg(subnet, crossMsg);
}

/// @notice release() burns the received value locally in subnet and commits a bottom-up message to release the assets in the parent.
Expand Down
64 changes: 31 additions & 33 deletions contracts/contracts/gateway/GatewayMessengerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,41 @@ pragma solidity ^0.8.23;
import {GatewayActorModifiers} from "../lib/LibGatewayActorStorage.sol";
import {IpcEnvelope, CallMsg, IpcMsgKind} from "../structs/CrossNet.sol";
import {IPCMsgType} from "../enums/IPCMsgType.sol";
import {SubnetID, AssetKind, IPCAddress} from "../structs/Subnet.sol";
import {InvalidXnetMessage, InvalidXnetMessageReason, CannotSendCrossMsgToItself, MethodNotAllowed} from "../errors/IPCErrors.sol";
import {Subnet, SubnetID, AssetKind, IPCAddress, Asset} from "../structs/Subnet.sol";
import {InvalidXnetMessage, InvalidXnetMessageReason, MethodNotAllowed} from "../errors/IPCErrors.sol";
import {SubnetIDHelper} from "../lib/SubnetIDHelper.sol";
import {LibGateway} from "../lib/LibGateway.sol";
import {FilAddress} from "fevmate/contracts/utils/FilAddress.sol";
import {AssetHelper} from "../lib/AssetHelper.sol";
import {CrossMsgHelper} from "../lib/CrossMsgHelper.sol";
import {FvmAddressHelper} from "../lib/FvmAddressHelper.sol";
import {ISubnetActor} from "../interfaces/ISubnetActor.sol";

import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

string constant ERR_GENERAL_CROSS_MSG_DISABLED = "Support for general-purpose cross-net messages is disabled";
string constant ERR_MULTILEVEL_CROSS_MSG_DISABLED = "Support for multi-level cross-net messages is disabled";

contract GatewayMessengerFacet is GatewayActorModifiers {
using FilAddress for address payable;
using SubnetIDHelper for SubnetID;
using EnumerableSet for EnumerableSet.Bytes32Set;
using CrossMsgHelper for IpcEnvelope;
using AssetHelper for Asset;

/**
* @dev Sends a general-purpose cross-message from the local subnet to the destination subnet.
* Any value in msg.value will be forwarded in the call.
* IMPORTANT: Native tokens via msg.value are treated as a contribution toward gas costs associated with message propagation.
* There is no strict enforcement of the exact gas cost, and any msg.value provided will be accepted.
*
* IMPORTANT: Only smart contracts are allowed to trigger these cross-net messages. User wallets can send funds
* from their address to the destination subnet and then run the transaction in the destination normally.
*
* @param envelope - the original envelope, which will be validated, stamped and committed during the send.
* @param envelope - the original envelope, which will be validated, stamped, and committed during the send.
* @return committed envelope.
*/
function sendContractXnetMessage(
IpcEnvelope calldata envelope
IpcEnvelope memory envelope
) external payable returns (IpcEnvelope memory committed) {
if (!s.generalPurposeCrossMsg) {
revert MethodNotAllowed(ERR_GENERAL_CROSS_MSG_DISABLED);
Expand All @@ -42,28 +49,33 @@ contract GatewayMessengerFacet is GatewayActorModifiers {
revert InvalidXnetMessage(InvalidXnetMessageReason.Sender);
}

if (envelope.value != msg.value) {
revert InvalidXnetMessage(InvalidXnetMessageReason.Value);
}

if (envelope.kind != IpcMsgKind.Call) {
revert InvalidXnetMessage(InvalidXnetMessageReason.Kind);
}

// Will revert if the message won't deserialize into a CallMsg.
abi.decode(envelope.message, (CallMsg));

committed = IpcEnvelope({
kind: IpcMsgKind.Call,
from: IPCAddress({subnetId: s.networkName, rawAddress: FvmAddressHelper.from(msg.sender)}),
to: envelope.to,
value: msg.value,
value: envelope.value,
message: envelope.message,
nonce: 0 // nonce will be updated by LibGateway.commitCrossMessage
// nonce and originalNonce will be updated by LibGateway.commitValidatedCrossMessage
originalNonce: 0,
localNonce: 0
});

(bool valid, InvalidXnetMessageReason reason, IPCMsgType applyType) = committed.validateCrossMessage();
if (!valid) {
revert InvalidXnetMessage(reason);
}

if (applyType == IPCMsgType.TopDown) {
(, SubnetID memory nextHop) = committed.to.subnetId.down(s.networkName);
// lock funds on the current subnet gateway for the next hop
ISubnetActor(nextHop.getActor()).supplySource().lock(envelope.value);
}

// Commit xnet message for dispatch.
bool shouldBurn = LibGateway.commitCrossMessage(committed);
bool shouldBurn = LibGateway.commitValidatedCrossMessage(committed);

// Apply side effects, such as burning funds.
LibGateway.crossMsgSideEffects({v: committed.value, shouldBurn: shouldBurn});
Expand All @@ -75,23 +87,9 @@ contract GatewayMessengerFacet is GatewayActorModifiers {
}

/**
* @dev propagates the populated cross net message for the given cid
* @param msgCid - the cid of the cross-net message
* @dev Propagates all the populated cross-net messages from the postbox.
*/
function propagate(bytes32 msgCid) external payable {
if (!s.multiLevelCrossMsg) {
revert MethodNotAllowed(ERR_MULTILEVEL_CROSS_MSG_DISABLED);
}

IpcEnvelope storage crossMsg = s.postbox[msgCid];

bool shouldBurn = LibGateway.commitCrossMessage(crossMsg);
// We must delete the message first to prevent potential re-entrancies,
// and as the message is deleted and we don't have a reference to the object
// anymore, we need to pull the data from the message to trigger the side-effects.
uint256 v = crossMsg.value;
delete s.postbox[msgCid];

LibGateway.crossMsgSideEffects({v: v, shouldBurn: shouldBurn});
function propagateAll() external payable {
LibGateway.propagateAllPostboxMessages();
}
}
11 changes: 9 additions & 2 deletions contracts/contracts/gateway/router/CheckpointingFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {NotRegisteredSubnet, SubnetNotActive, SubnetNotFound, InvalidSubnet, Che
import {BatchNotCreated, InvalidBatchEpoch, BatchAlreadyExists, NotEnoughSubnetCircSupply, InvalidCheckpointEpoch} from "../../errors/IPCErrors.sol";

import {CrossMsgHelper} from "../../lib/CrossMsgHelper.sol";
import {IpcEnvelope, SubnetID} from "../../structs/CrossNet.sol";
import {IpcEnvelope, SubnetID, IpcMsgKind} from "../../structs/CrossNet.sol";
import {SubnetIDHelper} from "../../lib/SubnetIDHelper.sol";

import {ActivityRollupRecorded, FullActivityRollup} from "../../structs/Activity.sol";
Expand All @@ -23,6 +23,9 @@ contract CheckpointingFacet is GatewayActorModifiers {
using SubnetIDHelper for SubnetID;
using CrossMsgHelper for IpcEnvelope;

/// @dev Emitted when a checkpoint is committed to gateway.
event CheckpointCommitted(address indexed subnet, uint256 subnetHeight);

/// @notice submit a verified checkpoint in the gateway to trigger side-effects.
/// @dev this method is called by the corresponding subnet actor.
/// Called from a subnet actor if the checkpoint is cryptographically valid.
Expand All @@ -43,6 +46,8 @@ contract CheckpointingFacet is GatewayActorModifiers {
LibGateway.checkMsgLength(checkpoint.msgs);

execBottomUpMsgs(checkpoint.msgs, subnet);

emit CheckpointCommitted({subnet: checkpoint.subnetID.getAddress(), subnetHeight: checkpoint.blockHeight});
}

/// @notice creates a new bottom-up checkpoint
Expand Down Expand Up @@ -129,7 +134,9 @@ contract CheckpointingFacet is GatewayActorModifiers {
uint256 crossMsgLength = msgs.length;

for (uint256 i; i < crossMsgLength; ) {
totalValue += msgs[i].value;
if (msgs[i].kind != IpcMsgKind.Call) {
totalValue += msgs[i].value;
}
unchecked {
++i;
}
Expand Down
3 changes: 2 additions & 1 deletion contracts/contracts/gateway/router/XnetMessagingFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ 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);
LibGateway.propagateAllPostboxMessages();
}
}
4 changes: 2 additions & 2 deletions contracts/contracts/interfaces/IGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ interface IGateway {
IpcEnvelope calldata envelope
) external payable returns (IpcEnvelope memory committed);

/// @notice Propagates the stored postbox item for the given cid
function propagate(bytes32 msgCid) external payable;
/// @notice Propagates all the stored messages to destination subnet
function propagateAll() external payable;

/// @notice commit the ipc parent finality into storage
function commitParentFinality(ParentFinality calldata finality) external;
Expand Down
9 changes: 9 additions & 0 deletions contracts/contracts/interfaces/ISubnetActor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity ^0.8.23;

import {Asset} from "../structs/Subnet.sol";

/// @title Subnet actor interface
interface ISubnetActor {
function supplySource() external view returns (Asset memory);
}
Loading
Loading