diff --git a/contracts/.storage-layouts/GatewayActorModifiers.json b/contracts/.storage-layouts/GatewayActorModifiers.json index b2f59a894..9f79cde9e 100644 --- a/contracts/.storage-layouts/GatewayActorModifiers.json +++ b/contracts/.storage-layouts/GatewayActorModifiers.json @@ -1,12 +1,12 @@ { "storage": [ { - "astId": 11959, + "astId": 14575, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "s", "offset": 0, "slot": "0", - "type": "t_struct(GatewayActorStorage)11945_storage" + "type": "t_struct(GatewayActorStorage)14561_storage" } ], "types": { @@ -27,14 +27,14 @@ "label": "bytes32[]", "numberOfBytes": "32" }, - "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage": { - "base": "t_struct(IpcEnvelope)19408_storage", + "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage": { + "base": "t_struct(IpcEnvelope)21402_storage", "encoding": "dynamic_array", "label": "struct IpcEnvelope[]", "numberOfBytes": "32" }, - "t_array(t_struct(Validator)19672_storage)dyn_storage": { - "base": "t_struct(Validator)19672_storage", + "t_array(t_struct(Validator)21666_storage)dyn_storage": { + "base": "t_struct(Validator)21666_storage", "encoding": "dynamic_array", "label": "struct Validator[]", "numberOfBytes": "32" @@ -54,22 +54,22 @@ "label": "bytes", "numberOfBytes": "32" }, - "t_enum(IpcMsgKind)19385": { + "t_enum(IpcMsgKind)21376": { "encoding": "inplace", "label": "enum IpcMsgKind", "numberOfBytes": "1" }, - "t_enum(PermissionMode)19618": { + "t_enum(PermissionMode)21612": { "encoding": "inplace", "label": "enum PermissionMode", "numberOfBytes": "1" }, - "t_enum(QuorumObjKind)19454": { + "t_enum(QuorumObjKind)21448": { "encoding": "inplace", "label": "enum QuorumObjKind", "numberOfBytes": "1" }, - "t_enum(StakingOperation)19541": { + "t_enum(StakingOperation)21535": { "encoding": "inplace", "label": "enum StakingOperation", "numberOfBytes": "1" @@ -81,12 +81,12 @@ "numberOfBytes": "32", "value": "t_bytes_storage" }, - "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)": { + "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct ValidatorInfo)", "numberOfBytes": "32", - "value": "t_struct(ValidatorInfo)19613_storage" + "value": "t_struct(ValidatorInfo)21607_storage" }, "t_mapping(t_address,t_uint16)": { "encoding": "mapping", @@ -95,19 +95,19 @@ "numberOfBytes": "32", "value": "t_uint16" }, - "t_mapping(t_bytes32,t_struct(IpcEnvelope)19408_storage)": { + "t_mapping(t_bytes32,t_struct(IpcEnvelope)21402_storage)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => struct IpcEnvelope)", "numberOfBytes": "32", - "value": "t_struct(IpcEnvelope)19408_storage" + "value": "t_struct(IpcEnvelope)21402_storage" }, - "t_mapping(t_bytes32,t_struct(Subnet)19535_storage)": { + "t_mapping(t_bytes32,t_struct(Subnet)21529_storage)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => struct Subnet)", "numberOfBytes": "32", - "value": "t_struct(Subnet)19535_storage" + "value": "t_struct(Subnet)21529_storage" }, "t_mapping(t_bytes32,t_uint256)": { "encoding": "mapping", @@ -130,77 +130,100 @@ "numberOfBytes": "32", "value": "t_mapping(t_address,t_bytes_storage)" }, - "t_mapping(t_uint256,t_struct(AddressSet)3459_storage)": { + "t_mapping(t_uint256,t_struct(AddressSet)4206_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct EnumerableSet.AddressSet)", "numberOfBytes": "32", - "value": "t_struct(AddressSet)3459_storage" + "value": "t_struct(AddressSet)4206_storage" }, - "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)": { + "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct BottomUpCheckpoint)", "numberOfBytes": "32", - "value": "t_struct(BottomUpCheckpoint)19331_storage" + "value": "t_struct(BottomUpCheckpoint)21351_storage" }, - "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)19374_storage)": { + "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)21365_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct BottomUpMsgBatch)", "numberOfBytes": "32", - "value": "t_struct(BottomUpMsgBatch)19374_storage" + "value": "t_struct(BottomUpMsgBatch)21365_storage" }, - "t_mapping(t_uint256,t_struct(ParentFinality)19311_storage)": { + "t_mapping(t_uint256,t_struct(ParentFinality)21327_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct ParentFinality)", "numberOfBytes": "32", - "value": "t_struct(ParentFinality)19311_storage" + "value": "t_struct(ParentFinality)21327_storage" }, - "t_mapping(t_uint256,t_struct(QuorumInfo)19471_storage)": { + "t_mapping(t_uint256,t_struct(QuorumInfo)21465_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct QuorumInfo)", "numberOfBytes": "32", - "value": "t_struct(QuorumInfo)19471_storage" + "value": "t_struct(QuorumInfo)21465_storage" }, - "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)": { + "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)": { "encoding": "mapping", "key": "t_uint64", "label": "mapping(uint64 => struct StakingChange)", "numberOfBytes": "32", - "value": "t_struct(StakingChange)19550_storage" + "value": "t_struct(StakingChange)21544_storage" }, - "t_struct(AddressSet)3459_storage": { + "t_struct(AddressSet)4206_storage": { "encoding": "inplace", "label": "struct EnumerableSet.AddressSet", "members": [ { - "astId": 3458, + "astId": 4205, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" } ], "numberOfBytes": "64" }, - "t_struct(BottomUpCheckpoint)19331_storage": { + "t_struct(AggregatedStats)21272_storage": { + "encoding": "inplace", + "label": "struct Consensus.AggregatedStats", + "members": [ + { + "astId": 21268, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "totalActiveValidators", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 21271, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "totalNumBlocksCommitted", + "offset": 8, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(BottomUpCheckpoint)21351_storage": { "encoding": "inplace", "label": "struct BottomUpCheckpoint", "members": [ { - "astId": 19316, + "astId": 21332, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "subnetID", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19319, + "astId": 21335, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "blockHeight", "offset": 0, @@ -208,7 +231,7 @@ "type": "t_uint256" }, { - "astId": 19322, + "astId": 21338, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "blockHash", "offset": 0, @@ -216,7 +239,7 @@ "type": "t_bytes32" }, { - "astId": 19325, + "astId": 21341, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "nextConfigurationNumber", "offset": 0, @@ -224,30 +247,38 @@ "type": "t_uint64" }, { - "astId": 19330, + "astId": 21346, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "msgs", "offset": 0, "slot": "5", - "type": "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage" + "type": "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage" + }, + { + "astId": 21350, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "activity", + "offset": 0, + "slot": "6", + "type": "t_struct(CompressedActivityRollup)21262_storage" } ], - "numberOfBytes": "192" + "numberOfBytes": "256" }, - "t_struct(BottomUpMsgBatch)19374_storage": { + "t_struct(BottomUpMsgBatch)21365_storage": { "encoding": "inplace", "label": "struct BottomUpMsgBatch", "members": [ { - "astId": 19365, + "astId": 21356, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "subnetID", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19368, + "astId": 21359, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "blockHeight", "offset": 0, @@ -255,37 +286,75 @@ "type": "t_uint256" }, { - "astId": 19373, + "astId": 21364, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "msgs", "offset": 0, "slot": "3", - "type": "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage" + "type": "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage" } ], "numberOfBytes": "128" }, - "t_struct(Bytes32Set)3338_storage": { + "t_struct(Bytes32Set)4085_storage": { "encoding": "inplace", "label": "struct EnumerableSet.Bytes32Set", "members": [ { - "astId": 3337, + "astId": 4084, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" + } + ], + "numberOfBytes": "64" + }, + "t_struct(CompressedActivityRollup)21262_storage": { + "encoding": "inplace", + "label": "struct CompressedActivityRollup", + "members": [ + { + "astId": 21261, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "consensus", + "offset": 0, + "slot": "0", + "type": "t_struct(CompressedSummary)21289_storage" + } + ], + "numberOfBytes": "64" + }, + "t_struct(CompressedSummary)21289_storage": { + "encoding": "inplace", + "label": "struct Consensus.CompressedSummary", + "members": [ + { + "astId": 21284, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "stats", + "offset": 0, + "slot": "0", + "type": "t_struct(AggregatedStats)21272_storage" + }, + { + "astId": 21288, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "dataRootCommitment", + "offset": 0, + "slot": "1", + "type": "t_userDefinedValueType(MerkleHash)21265" } ], "numberOfBytes": "64" }, - "t_struct(FvmAddress)19439_storage": { + "t_struct(FvmAddress)21433_storage": { "encoding": "inplace", "label": "struct FvmAddress", "members": [ { - "astId": 19436, + "astId": 21430, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "addrType", "offset": 0, @@ -293,7 +362,7 @@ "type": "t_uint8" }, { - "astId": 19438, + "astId": 21432, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "payload", "offset": 0, @@ -303,12 +372,12 @@ ], "numberOfBytes": "64" }, - "t_struct(GatewayActorStorage)11945_storage": { + "t_struct(GatewayActorStorage)14561_storage": { "encoding": "inplace", "label": "struct GatewayActorStorage", "members": [ { - "astId": 11857, + "astId": 14469, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "latestParentHeight", "offset": 0, @@ -316,7 +385,7 @@ "type": "t_uint256" }, { - "astId": 11860, + "astId": 14472, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "bottomUpCheckPeriod", "offset": 0, @@ -324,7 +393,7 @@ "type": "t_uint256" }, { - "astId": 11863, + "astId": 14475, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "bottomUpMsgBatchPeriod", "offset": 0, @@ -332,7 +401,7 @@ "type": "t_uint256" }, { - "astId": 11866, + "astId": 14478, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "bottomUpNonce", "offset": 0, @@ -340,7 +409,7 @@ "type": "t_uint64" }, { - "astId": 11869, + "astId": 14481, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "appliedTopDownNonce", "offset": 8, @@ -348,7 +417,7 @@ "type": "t_uint64" }, { - "astId": 11872, + "astId": 14484, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "totalSubnets", "offset": 16, @@ -356,7 +425,7 @@ "type": "t_uint64" }, { - "astId": 11875, + "astId": 14487, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "maxMsgsPerBottomUpBatch", "offset": 24, @@ -364,7 +433,7 @@ "type": "t_uint64" }, { - "astId": 11878, + "astId": 14490, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "majorityPercentage", "offset": 0, @@ -372,7 +441,7 @@ "type": "t_uint8" }, { - "astId": 11881, + "astId": 14493, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "commitSha", "offset": 0, @@ -380,7 +449,7 @@ "type": "t_bytes32" }, { - "astId": 11884, + "astId": 14496, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "maxTreeDepth", "offset": 0, @@ -388,7 +457,7 @@ "type": "t_uint8" }, { - "astId": 11887, + "astId": 14499, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "generalPurposeCrossMsg", "offset": 1, @@ -396,7 +465,7 @@ "type": "t_bool" }, { - "astId": 11890, + "astId": 14502, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "multiLevelCrossMsg", "offset": 2, @@ -404,157 +473,165 @@ "type": "t_bool" }, { - "astId": 11894, + "astId": 14506, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "currentMembership", "offset": 0, "slot": "7", - "type": "t_struct(Membership)19680_storage" + "type": "t_struct(Membership)21674_storage" }, { - "astId": 11898, + "astId": 14510, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "lastMembership", "offset": 0, "slot": "9", - "type": "t_struct(Membership)19680_storage" + "type": "t_struct(Membership)21674_storage" }, { - "astId": 11902, + "astId": 14514, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "checkpointQuorumMap", "offset": 0, "slot": "11", - "type": "t_struct(QuorumMap)19503_storage" + "type": "t_struct(QuorumMap)21497_storage" }, { - "astId": 11906, + "astId": 14518, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "networkName", "offset": 0, "slot": "18", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 11910, + "astId": 14522, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "validatorsTracker", "offset": 0, "slot": "20", - "type": "t_struct(ParentValidatorsTracker)19656_storage" + "type": "t_struct(ParentValidatorsTracker)21650_storage" }, { - "astId": 11916, + "astId": 14528, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "subnets", "offset": 0, "slot": "31", - "type": "t_mapping(t_bytes32,t_struct(Subnet)19535_storage)" + "type": "t_mapping(t_bytes32,t_struct(Subnet)21529_storage)" }, { - "astId": 11922, + "astId": 14534, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "finalitiesMap", "offset": 0, "slot": "32", - "type": "t_mapping(t_uint256,t_struct(ParentFinality)19311_storage)" + "type": "t_mapping(t_uint256,t_struct(ParentFinality)21327_storage)" }, { - "astId": 11928, + "astId": 14540, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "postbox", "offset": 0, "slot": "33", - "type": "t_mapping(t_bytes32,t_struct(IpcEnvelope)19408_storage)" + "type": "t_mapping(t_bytes32,t_struct(IpcEnvelope)21402_storage)" }, { - "astId": 11934, + "astId": 14544, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", - "label": "bottomUpCheckpoints", + "label": "postboxKeys", "offset": 0, "slot": "34", - "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)" + "type": "t_struct(Bytes32Set)4085_storage" + }, + { + "astId": 14550, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "bottomUpCheckpoints", + "offset": 0, + "slot": "36", + "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)" }, { - "astId": 11940, + "astId": 14556, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "bottomUpMsgBatches", "offset": 0, - "slot": "35", - "type": "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)19374_storage)" + "slot": "37", + "type": "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)21365_storage)" }, { - "astId": 11944, + "astId": 14560, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "subnetKeys", "offset": 0, - "slot": "36", - "type": "t_struct(Bytes32Set)3338_storage" + "slot": "38", + "type": "t_struct(Bytes32Set)4085_storage" } ], - "numberOfBytes": "1216" + "numberOfBytes": "1280" }, - "t_struct(IPCAddress)19664_storage": { + "t_struct(IPCAddress)21658_storage": { "encoding": "inplace", "label": "struct IPCAddress", "members": [ { - "astId": 19660, + "astId": 21654, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "subnetId", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19663, + "astId": 21657, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "rawAddress", "offset": 0, "slot": "2", - "type": "t_struct(FvmAddress)19439_storage" + "type": "t_struct(FvmAddress)21433_storage" } ], "numberOfBytes": "128" }, - "t_struct(IpcEnvelope)19408_storage": { + "t_struct(IpcEnvelope)21402_storage": { "encoding": "inplace", "label": "struct IpcEnvelope", "members": [ { - "astId": 19390, + "astId": 21381, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "kind", "offset": 0, "slot": "0", - "type": "t_enum(IpcMsgKind)19385" + "type": "t_enum(IpcMsgKind)21376" }, { - "astId": 19394, + "astId": 21385, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "to", "offset": 0, "slot": "1", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19398, + "astId": 21389, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "from", "offset": 0, "slot": "5", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19401, + "astId": 21392, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", - "label": "nonce", + "label": "localNonce", "offset": 0, "slot": "9", "type": "t_uint64" }, { - "astId": 19404, + "astId": 21395, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "value", "offset": 0, @@ -562,45 +639,53 @@ "type": "t_uint256" }, { - "astId": 19407, + "astId": 21398, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "message", "offset": 0, "slot": "11", "type": "t_bytes_storage" + }, + { + "astId": 21401, + "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", + "label": "originalNonce", + "offset": 0, + "slot": "12", + "type": "t_uint64" } ], - "numberOfBytes": "384" + "numberOfBytes": "416" }, - "t_struct(MaxPQ)17052_storage": { + "t_struct(MaxPQ)19752_storage": { "encoding": "inplace", "label": "struct MaxPQ", "members": [ { - "astId": 17051, + "astId": 19751, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(Membership)19680_storage": { + "t_struct(Membership)21674_storage": { "encoding": "inplace", "label": "struct Membership", "members": [ { - "astId": 19677, + "astId": 21671, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "validators", "offset": 0, "slot": "0", - "type": "t_array(t_struct(Validator)19672_storage)dyn_storage" + "type": "t_array(t_struct(Validator)21666_storage)dyn_storage" }, { - "astId": 19679, + "astId": 21673, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "configurationNumber", "offset": 0, @@ -610,27 +695,27 @@ ], "numberOfBytes": "64" }, - "t_struct(MinPQ)17670_storage": { + "t_struct(MinPQ)20370_storage": { "encoding": "inplace", "label": "struct MinPQ", "members": [ { - "astId": 17669, + "astId": 20369, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(PQ)18300_storage": { + "t_struct(PQ)21000_storage": { "encoding": "inplace", "label": "struct PQ", "members": [ { - "astId": 18289, + "astId": 20989, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "size", "offset": 0, @@ -638,7 +723,7 @@ "type": "t_uint16" }, { - "astId": 18294, + "astId": 20994, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "addressToPos", "offset": 0, @@ -646,7 +731,7 @@ "type": "t_mapping(t_address,t_uint16)" }, { - "astId": 18299, + "astId": 20999, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "posToAddress", "offset": 0, @@ -656,12 +741,12 @@ ], "numberOfBytes": "96" }, - "t_struct(ParentFinality)19311_storage": { + "t_struct(ParentFinality)21327_storage": { "encoding": "inplace", "label": "struct ParentFinality", "members": [ { - "astId": 19308, + "astId": 21324, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "height", "offset": 0, @@ -669,7 +754,7 @@ "type": "t_uint256" }, { - "astId": 19310, + "astId": 21326, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "blockHash", "offset": 0, @@ -679,35 +764,35 @@ ], "numberOfBytes": "64" }, - "t_struct(ParentValidatorsTracker)19656_storage": { + "t_struct(ParentValidatorsTracker)21650_storage": { "encoding": "inplace", "label": "struct ParentValidatorsTracker", "members": [ { - "astId": 19652, + "astId": 21646, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "validators", "offset": 0, "slot": "0", - "type": "t_struct(ValidatorSet)19648_storage" + "type": "t_struct(ValidatorSet)21642_storage" }, { - "astId": 19655, + "astId": 21649, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "changes", "offset": 0, "slot": "9", - "type": "t_struct(StakingChangeLog)19571_storage" + "type": "t_struct(StakingChangeLog)21565_storage" } ], "numberOfBytes": "352" }, - "t_struct(QuorumInfo)19471_storage": { + "t_struct(QuorumInfo)21465_storage": { "encoding": "inplace", "label": "struct QuorumInfo", "members": [ { - "astId": 19458, + "astId": 21452, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "hash", "offset": 0, @@ -715,7 +800,7 @@ "type": "t_bytes32" }, { - "astId": 19461, + "astId": 21455, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "rootHash", "offset": 0, @@ -723,7 +808,7 @@ "type": "t_bytes32" }, { - "astId": 19464, + "astId": 21458, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "threshold", "offset": 0, @@ -731,7 +816,7 @@ "type": "t_uint256" }, { - "astId": 19467, + "astId": 21461, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "currentWeight", "offset": 0, @@ -739,7 +824,7 @@ "type": "t_uint256" }, { - "astId": 19470, + "astId": 21464, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "reached", "offset": 0, @@ -749,20 +834,20 @@ ], "numberOfBytes": "160" }, - "t_struct(QuorumMap)19503_storage": { + "t_struct(QuorumMap)21497_storage": { "encoding": "inplace", "label": "struct QuorumMap", "members": [ { - "astId": 19476, + "astId": 21470, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "quorumObjKind", "offset": 0, "slot": "0", - "type": "t_enum(QuorumObjKind)19454" + "type": "t_enum(QuorumObjKind)21448" }, { - "astId": 19479, + "astId": 21473, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "retentionHeight", "offset": 0, @@ -770,31 +855,31 @@ "type": "t_uint256" }, { - "astId": 19485, + "astId": 21479, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "quorumInfo", "offset": 0, "slot": "2", - "type": "t_mapping(t_uint256,t_struct(QuorumInfo)19471_storage)" + "type": "t_mapping(t_uint256,t_struct(QuorumInfo)21465_storage)" }, { - "astId": 19489, + "astId": 21483, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "incompleteQuorums", "offset": 0, "slot": "3", - "type": "t_struct(UintSet)3616_storage" + "type": "t_struct(UintSet)4363_storage" }, { - "astId": 19495, + "astId": 21489, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "quorumSignatureSenders", "offset": 0, "slot": "5", - "type": "t_mapping(t_uint256,t_struct(AddressSet)3459_storage)" + "type": "t_mapping(t_uint256,t_struct(AddressSet)4206_storage)" }, { - "astId": 19502, + "astId": 21496, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "quorumSignatures", "offset": 0, @@ -804,12 +889,12 @@ ], "numberOfBytes": "224" }, - "t_struct(Set)3144_storage": { + "t_struct(Set)3891_storage": { "encoding": "inplace", "label": "struct EnumerableSet.Set", "members": [ { - "astId": 3139, + "astId": 3886, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "_values", "offset": 0, @@ -817,7 +902,7 @@ "type": "t_array(t_bytes32)dyn_storage" }, { - "astId": 3143, + "astId": 3890, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "_positions", "offset": 0, @@ -827,20 +912,20 @@ ], "numberOfBytes": "64" }, - "t_struct(StakingChange)19550_storage": { + "t_struct(StakingChange)21544_storage": { "encoding": "inplace", "label": "struct StakingChange", "members": [ { - "astId": 19545, + "astId": 21539, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "op", "offset": 0, "slot": "0", - "type": "t_enum(StakingOperation)19541" + "type": "t_enum(StakingOperation)21535" }, { - "astId": 19547, + "astId": 21541, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "payload", "offset": 0, @@ -848,7 +933,7 @@ "type": "t_bytes_storage" }, { - "astId": 19549, + "astId": 21543, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "validator", "offset": 0, @@ -858,12 +943,12 @@ ], "numberOfBytes": "96" }, - "t_struct(StakingChangeLog)19571_storage": { + "t_struct(StakingChangeLog)21565_storage": { "encoding": "inplace", "label": "struct StakingChangeLog", "members": [ { - "astId": 19561, + "astId": 21555, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "nextConfigurationNumber", "offset": 0, @@ -871,7 +956,7 @@ "type": "t_uint64" }, { - "astId": 19564, + "astId": 21558, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "startConfigurationNumber", "offset": 8, @@ -879,22 +964,22 @@ "type": "t_uint64" }, { - "astId": 19570, + "astId": 21564, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "changes", "offset": 0, "slot": "1", - "type": "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)" + "type": "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)" } ], "numberOfBytes": "64" }, - "t_struct(Subnet)19535_storage": { + "t_struct(Subnet)21529_storage": { "encoding": "inplace", "label": "struct Subnet", "members": [ { - "astId": 19523, + "astId": 21517, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "stake", "offset": 0, @@ -902,7 +987,7 @@ "type": "t_uint256" }, { - "astId": 19525, + "astId": 21519, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "genesisEpoch", "offset": 0, @@ -910,7 +995,7 @@ "type": "t_uint256" }, { - "astId": 19527, + "astId": 21521, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "circSupply", "offset": 0, @@ -918,7 +1003,7 @@ "type": "t_uint256" }, { - "astId": 19529, + "astId": 21523, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "topDownNonce", "offset": 0, @@ -926,7 +1011,7 @@ "type": "t_uint64" }, { - "astId": 19531, + "astId": 21525, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "appliedBottomUpNonce", "offset": 8, @@ -934,22 +1019,22 @@ "type": "t_uint64" }, { - "astId": 19534, + "astId": 21528, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "id", "offset": 0, "slot": "4", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" } ], "numberOfBytes": "192" }, - "t_struct(SubnetID)19520_storage": { + "t_struct(SubnetID)21514_storage": { "encoding": "inplace", "label": "struct SubnetID", "members": [ { - "astId": 19515, + "astId": 21509, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "root", "offset": 0, @@ -957,7 +1042,7 @@ "type": "t_uint64" }, { - "astId": 19519, + "astId": 21513, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "route", "offset": 0, @@ -967,27 +1052,27 @@ ], "numberOfBytes": "64" }, - "t_struct(UintSet)3616_storage": { + "t_struct(UintSet)4363_storage": { "encoding": "inplace", "label": "struct EnumerableSet.UintSet", "members": [ { - "astId": 3615, + "astId": 4362, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" } ], "numberOfBytes": "64" }, - "t_struct(Validator)19672_storage": { + "t_struct(Validator)21666_storage": { "encoding": "inplace", "label": "struct Validator", "members": [ { - "astId": 19667, + "astId": 21661, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "weight", "offset": 0, @@ -995,7 +1080,7 @@ "type": "t_uint256" }, { - "astId": 19669, + "astId": 21663, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "addr", "offset": 0, @@ -1003,7 +1088,7 @@ "type": "t_address" }, { - "astId": 19671, + "astId": 21665, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "metadata", "offset": 0, @@ -1013,12 +1098,12 @@ ], "numberOfBytes": "96" }, - "t_struct(ValidatorInfo)19613_storage": { + "t_struct(ValidatorInfo)21607_storage": { "encoding": "inplace", "label": "struct ValidatorInfo", "members": [ { - "astId": 19605, + "astId": 21599, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "federatedPower", "offset": 0, @@ -1026,7 +1111,7 @@ "type": "t_uint256" }, { - "astId": 19607, + "astId": 21601, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "confirmedCollateral", "offset": 0, @@ -1034,7 +1119,7 @@ "type": "t_uint256" }, { - "astId": 19609, + "astId": 21603, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "totalCollateral", "offset": 0, @@ -1042,7 +1127,7 @@ "type": "t_uint256" }, { - "astId": 19612, + "astId": 21606, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "metadata", "offset": 0, @@ -1052,20 +1137,20 @@ ], "numberOfBytes": "128" }, - "t_struct(ValidatorSet)19648_storage": { + "t_struct(ValidatorSet)21642_storage": { "encoding": "inplace", "label": "struct ValidatorSet", "members": [ { - "astId": 19627, + "astId": 21621, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "permissionMode", "offset": 0, "slot": "0", - "type": "t_enum(PermissionMode)19618" + "type": "t_enum(PermissionMode)21612" }, { - "astId": 19630, + "astId": 21624, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "activeLimit", "offset": 1, @@ -1073,7 +1158,7 @@ "type": "t_uint16" }, { - "astId": 19633, + "astId": 21627, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "totalConfirmedCollateral", "offset": 0, @@ -1081,28 +1166,28 @@ "type": "t_uint256" }, { - "astId": 19639, + "astId": 21633, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "validators", "offset": 0, "slot": "2", - "type": "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)" + "type": "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)" }, { - "astId": 19643, + "astId": 21637, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "activeValidators", "offset": 0, "slot": "3", - "type": "t_struct(MinPQ)17670_storage" + "type": "t_struct(MinPQ)20370_storage" }, { - "astId": 19647, + "astId": 21641, "contract": "contracts/lib/LibGatewayActorStorage.sol:GatewayActorModifiers", "label": "waitingValidators", "offset": 0, "slot": "6", - "type": "t_struct(MaxPQ)17052_storage" + "type": "t_struct(MaxPQ)19752_storage" } ], "numberOfBytes": "288" @@ -1126,6 +1211,11 @@ "encoding": "inplace", "label": "uint8", "numberOfBytes": "1" + }, + "t_userDefinedValueType(MerkleHash)21265": { + "encoding": "inplace", + "label": "Consensus.MerkleHash", + "numberOfBytes": "32" } } } diff --git a/contracts/.storage-layouts/GatewayDiamond.json b/contracts/.storage-layouts/GatewayDiamond.json index a40c2ec87..368d42df7 100644 --- a/contracts/.storage-layouts/GatewayDiamond.json +++ b/contracts/.storage-layouts/GatewayDiamond.json @@ -1,12 +1,12 @@ { "storage": [ { - "astId": 3792, + "astId": 4539, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "s", "offset": 0, "slot": "0", - "type": "t_struct(GatewayActorStorage)11945_storage" + "type": "t_struct(GatewayActorStorage)14561_storage" } ], "types": { @@ -27,14 +27,14 @@ "label": "bytes32[]", "numberOfBytes": "32" }, - "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage": { - "base": "t_struct(IpcEnvelope)19408_storage", + "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage": { + "base": "t_struct(IpcEnvelope)21402_storage", "encoding": "dynamic_array", "label": "struct IpcEnvelope[]", "numberOfBytes": "32" }, - "t_array(t_struct(Validator)19672_storage)dyn_storage": { - "base": "t_struct(Validator)19672_storage", + "t_array(t_struct(Validator)21666_storage)dyn_storage": { + "base": "t_struct(Validator)21666_storage", "encoding": "dynamic_array", "label": "struct Validator[]", "numberOfBytes": "32" @@ -54,22 +54,22 @@ "label": "bytes", "numberOfBytes": "32" }, - "t_enum(IpcMsgKind)19385": { + "t_enum(IpcMsgKind)21376": { "encoding": "inplace", "label": "enum IpcMsgKind", "numberOfBytes": "1" }, - "t_enum(PermissionMode)19618": { + "t_enum(PermissionMode)21612": { "encoding": "inplace", "label": "enum PermissionMode", "numberOfBytes": "1" }, - "t_enum(QuorumObjKind)19454": { + "t_enum(QuorumObjKind)21448": { "encoding": "inplace", "label": "enum QuorumObjKind", "numberOfBytes": "1" }, - "t_enum(StakingOperation)19541": { + "t_enum(StakingOperation)21535": { "encoding": "inplace", "label": "enum StakingOperation", "numberOfBytes": "1" @@ -81,12 +81,12 @@ "numberOfBytes": "32", "value": "t_bytes_storage" }, - "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)": { + "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct ValidatorInfo)", "numberOfBytes": "32", - "value": "t_struct(ValidatorInfo)19613_storage" + "value": "t_struct(ValidatorInfo)21607_storage" }, "t_mapping(t_address,t_uint16)": { "encoding": "mapping", @@ -95,19 +95,19 @@ "numberOfBytes": "32", "value": "t_uint16" }, - "t_mapping(t_bytes32,t_struct(IpcEnvelope)19408_storage)": { + "t_mapping(t_bytes32,t_struct(IpcEnvelope)21402_storage)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => struct IpcEnvelope)", "numberOfBytes": "32", - "value": "t_struct(IpcEnvelope)19408_storage" + "value": "t_struct(IpcEnvelope)21402_storage" }, - "t_mapping(t_bytes32,t_struct(Subnet)19535_storage)": { + "t_mapping(t_bytes32,t_struct(Subnet)21529_storage)": { "encoding": "mapping", "key": "t_bytes32", "label": "mapping(bytes32 => struct Subnet)", "numberOfBytes": "32", - "value": "t_struct(Subnet)19535_storage" + "value": "t_struct(Subnet)21529_storage" }, "t_mapping(t_bytes32,t_uint256)": { "encoding": "mapping", @@ -130,77 +130,100 @@ "numberOfBytes": "32", "value": "t_mapping(t_address,t_bytes_storage)" }, - "t_mapping(t_uint256,t_struct(AddressSet)3459_storage)": { + "t_mapping(t_uint256,t_struct(AddressSet)4206_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct EnumerableSet.AddressSet)", "numberOfBytes": "32", - "value": "t_struct(AddressSet)3459_storage" + "value": "t_struct(AddressSet)4206_storage" }, - "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)": { + "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct BottomUpCheckpoint)", "numberOfBytes": "32", - "value": "t_struct(BottomUpCheckpoint)19331_storage" + "value": "t_struct(BottomUpCheckpoint)21351_storage" }, - "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)19374_storage)": { + "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)21365_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct BottomUpMsgBatch)", "numberOfBytes": "32", - "value": "t_struct(BottomUpMsgBatch)19374_storage" + "value": "t_struct(BottomUpMsgBatch)21365_storage" }, - "t_mapping(t_uint256,t_struct(ParentFinality)19311_storage)": { + "t_mapping(t_uint256,t_struct(ParentFinality)21327_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct ParentFinality)", "numberOfBytes": "32", - "value": "t_struct(ParentFinality)19311_storage" + "value": "t_struct(ParentFinality)21327_storage" }, - "t_mapping(t_uint256,t_struct(QuorumInfo)19471_storage)": { + "t_mapping(t_uint256,t_struct(QuorumInfo)21465_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct QuorumInfo)", "numberOfBytes": "32", - "value": "t_struct(QuorumInfo)19471_storage" + "value": "t_struct(QuorumInfo)21465_storage" }, - "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)": { + "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)": { "encoding": "mapping", "key": "t_uint64", "label": "mapping(uint64 => struct StakingChange)", "numberOfBytes": "32", - "value": "t_struct(StakingChange)19550_storage" + "value": "t_struct(StakingChange)21544_storage" }, - "t_struct(AddressSet)3459_storage": { + "t_struct(AddressSet)4206_storage": { "encoding": "inplace", "label": "struct EnumerableSet.AddressSet", "members": [ { - "astId": 3458, + "astId": 4205, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" } ], "numberOfBytes": "64" }, - "t_struct(BottomUpCheckpoint)19331_storage": { + "t_struct(AggregatedStats)21272_storage": { + "encoding": "inplace", + "label": "struct Consensus.AggregatedStats", + "members": [ + { + "astId": 21268, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "totalActiveValidators", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 21271, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "totalNumBlocksCommitted", + "offset": 8, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(BottomUpCheckpoint)21351_storage": { "encoding": "inplace", "label": "struct BottomUpCheckpoint", "members": [ { - "astId": 19316, + "astId": 21332, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "subnetID", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19319, + "astId": 21335, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "blockHeight", "offset": 0, @@ -208,7 +231,7 @@ "type": "t_uint256" }, { - "astId": 19322, + "astId": 21338, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "blockHash", "offset": 0, @@ -216,7 +239,7 @@ "type": "t_bytes32" }, { - "astId": 19325, + "astId": 21341, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "nextConfigurationNumber", "offset": 0, @@ -224,30 +247,38 @@ "type": "t_uint64" }, { - "astId": 19330, + "astId": 21346, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "msgs", "offset": 0, "slot": "5", - "type": "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage" + "type": "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage" + }, + { + "astId": 21350, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "activity", + "offset": 0, + "slot": "6", + "type": "t_struct(CompressedActivityRollup)21262_storage" } ], - "numberOfBytes": "192" + "numberOfBytes": "256" }, - "t_struct(BottomUpMsgBatch)19374_storage": { + "t_struct(BottomUpMsgBatch)21365_storage": { "encoding": "inplace", "label": "struct BottomUpMsgBatch", "members": [ { - "astId": 19365, + "astId": 21356, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "subnetID", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19368, + "astId": 21359, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "blockHeight", "offset": 0, @@ -255,37 +286,75 @@ "type": "t_uint256" }, { - "astId": 19373, + "astId": 21364, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "msgs", "offset": 0, "slot": "3", - "type": "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage" + "type": "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage" } ], "numberOfBytes": "128" }, - "t_struct(Bytes32Set)3338_storage": { + "t_struct(Bytes32Set)4085_storage": { "encoding": "inplace", "label": "struct EnumerableSet.Bytes32Set", "members": [ { - "astId": 3337, + "astId": 4084, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" + } + ], + "numberOfBytes": "64" + }, + "t_struct(CompressedActivityRollup)21262_storage": { + "encoding": "inplace", + "label": "struct CompressedActivityRollup", + "members": [ + { + "astId": 21261, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "consensus", + "offset": 0, + "slot": "0", + "type": "t_struct(CompressedSummary)21289_storage" + } + ], + "numberOfBytes": "64" + }, + "t_struct(CompressedSummary)21289_storage": { + "encoding": "inplace", + "label": "struct Consensus.CompressedSummary", + "members": [ + { + "astId": 21284, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "stats", + "offset": 0, + "slot": "0", + "type": "t_struct(AggregatedStats)21272_storage" + }, + { + "astId": 21288, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "dataRootCommitment", + "offset": 0, + "slot": "1", + "type": "t_userDefinedValueType(MerkleHash)21265" } ], "numberOfBytes": "64" }, - "t_struct(FvmAddress)19439_storage": { + "t_struct(FvmAddress)21433_storage": { "encoding": "inplace", "label": "struct FvmAddress", "members": [ { - "astId": 19436, + "astId": 21430, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "addrType", "offset": 0, @@ -293,7 +362,7 @@ "type": "t_uint8" }, { - "astId": 19438, + "astId": 21432, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "payload", "offset": 0, @@ -303,12 +372,12 @@ ], "numberOfBytes": "64" }, - "t_struct(GatewayActorStorage)11945_storage": { + "t_struct(GatewayActorStorage)14561_storage": { "encoding": "inplace", "label": "struct GatewayActorStorage", "members": [ { - "astId": 11857, + "astId": 14469, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "latestParentHeight", "offset": 0, @@ -316,7 +385,7 @@ "type": "t_uint256" }, { - "astId": 11860, + "astId": 14472, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "bottomUpCheckPeriod", "offset": 0, @@ -324,7 +393,7 @@ "type": "t_uint256" }, { - "astId": 11863, + "astId": 14475, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "bottomUpMsgBatchPeriod", "offset": 0, @@ -332,7 +401,7 @@ "type": "t_uint256" }, { - "astId": 11866, + "astId": 14478, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "bottomUpNonce", "offset": 0, @@ -340,7 +409,7 @@ "type": "t_uint64" }, { - "astId": 11869, + "astId": 14481, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "appliedTopDownNonce", "offset": 8, @@ -348,7 +417,7 @@ "type": "t_uint64" }, { - "astId": 11872, + "astId": 14484, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "totalSubnets", "offset": 16, @@ -356,7 +425,7 @@ "type": "t_uint64" }, { - "astId": 11875, + "astId": 14487, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "maxMsgsPerBottomUpBatch", "offset": 24, @@ -364,7 +433,7 @@ "type": "t_uint64" }, { - "astId": 11878, + "astId": 14490, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "majorityPercentage", "offset": 0, @@ -372,7 +441,7 @@ "type": "t_uint8" }, { - "astId": 11881, + "astId": 14493, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "commitSha", "offset": 0, @@ -380,7 +449,7 @@ "type": "t_bytes32" }, { - "astId": 11884, + "astId": 14496, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "maxTreeDepth", "offset": 0, @@ -388,7 +457,7 @@ "type": "t_uint8" }, { - "astId": 11887, + "astId": 14499, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "generalPurposeCrossMsg", "offset": 1, @@ -396,7 +465,7 @@ "type": "t_bool" }, { - "astId": 11890, + "astId": 14502, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "multiLevelCrossMsg", "offset": 2, @@ -404,157 +473,165 @@ "type": "t_bool" }, { - "astId": 11894, + "astId": 14506, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "currentMembership", "offset": 0, "slot": "7", - "type": "t_struct(Membership)19680_storage" + "type": "t_struct(Membership)21674_storage" }, { - "astId": 11898, + "astId": 14510, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "lastMembership", "offset": 0, "slot": "9", - "type": "t_struct(Membership)19680_storage" + "type": "t_struct(Membership)21674_storage" }, { - "astId": 11902, + "astId": 14514, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "checkpointQuorumMap", "offset": 0, "slot": "11", - "type": "t_struct(QuorumMap)19503_storage" + "type": "t_struct(QuorumMap)21497_storage" }, { - "astId": 11906, + "astId": 14518, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "networkName", "offset": 0, "slot": "18", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 11910, + "astId": 14522, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "validatorsTracker", "offset": 0, "slot": "20", - "type": "t_struct(ParentValidatorsTracker)19656_storage" + "type": "t_struct(ParentValidatorsTracker)21650_storage" }, { - "astId": 11916, + "astId": 14528, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "subnets", "offset": 0, "slot": "31", - "type": "t_mapping(t_bytes32,t_struct(Subnet)19535_storage)" + "type": "t_mapping(t_bytes32,t_struct(Subnet)21529_storage)" }, { - "astId": 11922, + "astId": 14534, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "finalitiesMap", "offset": 0, "slot": "32", - "type": "t_mapping(t_uint256,t_struct(ParentFinality)19311_storage)" + "type": "t_mapping(t_uint256,t_struct(ParentFinality)21327_storage)" }, { - "astId": 11928, + "astId": 14540, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "postbox", "offset": 0, "slot": "33", - "type": "t_mapping(t_bytes32,t_struct(IpcEnvelope)19408_storage)" + "type": "t_mapping(t_bytes32,t_struct(IpcEnvelope)21402_storage)" }, { - "astId": 11934, + "astId": 14544, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", - "label": "bottomUpCheckpoints", + "label": "postboxKeys", "offset": 0, "slot": "34", - "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)" + "type": "t_struct(Bytes32Set)4085_storage" + }, + { + "astId": 14550, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "bottomUpCheckpoints", + "offset": 0, + "slot": "36", + "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)" }, { - "astId": 11940, + "astId": 14556, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "bottomUpMsgBatches", "offset": 0, - "slot": "35", - "type": "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)19374_storage)" + "slot": "37", + "type": "t_mapping(t_uint256,t_struct(BottomUpMsgBatch)21365_storage)" }, { - "astId": 11944, + "astId": 14560, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "subnetKeys", "offset": 0, - "slot": "36", - "type": "t_struct(Bytes32Set)3338_storage" + "slot": "38", + "type": "t_struct(Bytes32Set)4085_storage" } ], - "numberOfBytes": "1216" + "numberOfBytes": "1280" }, - "t_struct(IPCAddress)19664_storage": { + "t_struct(IPCAddress)21658_storage": { "encoding": "inplace", "label": "struct IPCAddress", "members": [ { - "astId": 19660, + "astId": 21654, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "subnetId", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19663, + "astId": 21657, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "rawAddress", "offset": 0, "slot": "2", - "type": "t_struct(FvmAddress)19439_storage" + "type": "t_struct(FvmAddress)21433_storage" } ], "numberOfBytes": "128" }, - "t_struct(IpcEnvelope)19408_storage": { + "t_struct(IpcEnvelope)21402_storage": { "encoding": "inplace", "label": "struct IpcEnvelope", "members": [ { - "astId": 19390, + "astId": 21381, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "kind", "offset": 0, "slot": "0", - "type": "t_enum(IpcMsgKind)19385" + "type": "t_enum(IpcMsgKind)21376" }, { - "astId": 19394, + "astId": 21385, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "to", "offset": 0, "slot": "1", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19398, + "astId": 21389, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "from", "offset": 0, "slot": "5", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19401, + "astId": 21392, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", - "label": "nonce", + "label": "localNonce", "offset": 0, "slot": "9", "type": "t_uint64" }, { - "astId": 19404, + "astId": 21395, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "value", "offset": 0, @@ -562,45 +639,53 @@ "type": "t_uint256" }, { - "astId": 19407, + "astId": 21398, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "message", "offset": 0, "slot": "11", "type": "t_bytes_storage" + }, + { + "astId": 21401, + "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", + "label": "originalNonce", + "offset": 0, + "slot": "12", + "type": "t_uint64" } ], - "numberOfBytes": "384" + "numberOfBytes": "416" }, - "t_struct(MaxPQ)17052_storage": { + "t_struct(MaxPQ)19752_storage": { "encoding": "inplace", "label": "struct MaxPQ", "members": [ { - "astId": 17051, + "astId": 19751, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(Membership)19680_storage": { + "t_struct(Membership)21674_storage": { "encoding": "inplace", "label": "struct Membership", "members": [ { - "astId": 19677, + "astId": 21671, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "validators", "offset": 0, "slot": "0", - "type": "t_array(t_struct(Validator)19672_storage)dyn_storage" + "type": "t_array(t_struct(Validator)21666_storage)dyn_storage" }, { - "astId": 19679, + "astId": 21673, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "configurationNumber", "offset": 0, @@ -610,27 +695,27 @@ ], "numberOfBytes": "64" }, - "t_struct(MinPQ)17670_storage": { + "t_struct(MinPQ)20370_storage": { "encoding": "inplace", "label": "struct MinPQ", "members": [ { - "astId": 17669, + "astId": 20369, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(PQ)18300_storage": { + "t_struct(PQ)21000_storage": { "encoding": "inplace", "label": "struct PQ", "members": [ { - "astId": 18289, + "astId": 20989, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "size", "offset": 0, @@ -638,7 +723,7 @@ "type": "t_uint16" }, { - "astId": 18294, + "astId": 20994, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "addressToPos", "offset": 0, @@ -646,7 +731,7 @@ "type": "t_mapping(t_address,t_uint16)" }, { - "astId": 18299, + "astId": 20999, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "posToAddress", "offset": 0, @@ -656,12 +741,12 @@ ], "numberOfBytes": "96" }, - "t_struct(ParentFinality)19311_storage": { + "t_struct(ParentFinality)21327_storage": { "encoding": "inplace", "label": "struct ParentFinality", "members": [ { - "astId": 19308, + "astId": 21324, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "height", "offset": 0, @@ -669,7 +754,7 @@ "type": "t_uint256" }, { - "astId": 19310, + "astId": 21326, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "blockHash", "offset": 0, @@ -679,35 +764,35 @@ ], "numberOfBytes": "64" }, - "t_struct(ParentValidatorsTracker)19656_storage": { + "t_struct(ParentValidatorsTracker)21650_storage": { "encoding": "inplace", "label": "struct ParentValidatorsTracker", "members": [ { - "astId": 19652, + "astId": 21646, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "validators", "offset": 0, "slot": "0", - "type": "t_struct(ValidatorSet)19648_storage" + "type": "t_struct(ValidatorSet)21642_storage" }, { - "astId": 19655, + "astId": 21649, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "changes", "offset": 0, "slot": "9", - "type": "t_struct(StakingChangeLog)19571_storage" + "type": "t_struct(StakingChangeLog)21565_storage" } ], "numberOfBytes": "352" }, - "t_struct(QuorumInfo)19471_storage": { + "t_struct(QuorumInfo)21465_storage": { "encoding": "inplace", "label": "struct QuorumInfo", "members": [ { - "astId": 19458, + "astId": 21452, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "hash", "offset": 0, @@ -715,7 +800,7 @@ "type": "t_bytes32" }, { - "astId": 19461, + "astId": 21455, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "rootHash", "offset": 0, @@ -723,7 +808,7 @@ "type": "t_bytes32" }, { - "astId": 19464, + "astId": 21458, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "threshold", "offset": 0, @@ -731,7 +816,7 @@ "type": "t_uint256" }, { - "astId": 19467, + "astId": 21461, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "currentWeight", "offset": 0, @@ -739,7 +824,7 @@ "type": "t_uint256" }, { - "astId": 19470, + "astId": 21464, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "reached", "offset": 0, @@ -749,20 +834,20 @@ ], "numberOfBytes": "160" }, - "t_struct(QuorumMap)19503_storage": { + "t_struct(QuorumMap)21497_storage": { "encoding": "inplace", "label": "struct QuorumMap", "members": [ { - "astId": 19476, + "astId": 21470, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "quorumObjKind", "offset": 0, "slot": "0", - "type": "t_enum(QuorumObjKind)19454" + "type": "t_enum(QuorumObjKind)21448" }, { - "astId": 19479, + "astId": 21473, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "retentionHeight", "offset": 0, @@ -770,31 +855,31 @@ "type": "t_uint256" }, { - "astId": 19485, + "astId": 21479, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "quorumInfo", "offset": 0, "slot": "2", - "type": "t_mapping(t_uint256,t_struct(QuorumInfo)19471_storage)" + "type": "t_mapping(t_uint256,t_struct(QuorumInfo)21465_storage)" }, { - "astId": 19489, + "astId": 21483, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "incompleteQuorums", "offset": 0, "slot": "3", - "type": "t_struct(UintSet)3616_storage" + "type": "t_struct(UintSet)4363_storage" }, { - "astId": 19495, + "astId": 21489, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "quorumSignatureSenders", "offset": 0, "slot": "5", - "type": "t_mapping(t_uint256,t_struct(AddressSet)3459_storage)" + "type": "t_mapping(t_uint256,t_struct(AddressSet)4206_storage)" }, { - "astId": 19502, + "astId": 21496, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "quorumSignatures", "offset": 0, @@ -804,12 +889,12 @@ ], "numberOfBytes": "224" }, - "t_struct(Set)3144_storage": { + "t_struct(Set)3891_storage": { "encoding": "inplace", "label": "struct EnumerableSet.Set", "members": [ { - "astId": 3139, + "astId": 3886, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "_values", "offset": 0, @@ -817,7 +902,7 @@ "type": "t_array(t_bytes32)dyn_storage" }, { - "astId": 3143, + "astId": 3890, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "_positions", "offset": 0, @@ -827,20 +912,20 @@ ], "numberOfBytes": "64" }, - "t_struct(StakingChange)19550_storage": { + "t_struct(StakingChange)21544_storage": { "encoding": "inplace", "label": "struct StakingChange", "members": [ { - "astId": 19545, + "astId": 21539, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "op", "offset": 0, "slot": "0", - "type": "t_enum(StakingOperation)19541" + "type": "t_enum(StakingOperation)21535" }, { - "astId": 19547, + "astId": 21541, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "payload", "offset": 0, @@ -848,7 +933,7 @@ "type": "t_bytes_storage" }, { - "astId": 19549, + "astId": 21543, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "validator", "offset": 0, @@ -858,12 +943,12 @@ ], "numberOfBytes": "96" }, - "t_struct(StakingChangeLog)19571_storage": { + "t_struct(StakingChangeLog)21565_storage": { "encoding": "inplace", "label": "struct StakingChangeLog", "members": [ { - "astId": 19561, + "astId": 21555, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "nextConfigurationNumber", "offset": 0, @@ -871,7 +956,7 @@ "type": "t_uint64" }, { - "astId": 19564, + "astId": 21558, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "startConfigurationNumber", "offset": 8, @@ -879,22 +964,22 @@ "type": "t_uint64" }, { - "astId": 19570, + "astId": 21564, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "changes", "offset": 0, "slot": "1", - "type": "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)" + "type": "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)" } ], "numberOfBytes": "64" }, - "t_struct(Subnet)19535_storage": { + "t_struct(Subnet)21529_storage": { "encoding": "inplace", "label": "struct Subnet", "members": [ { - "astId": 19523, + "astId": 21517, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "stake", "offset": 0, @@ -902,7 +987,7 @@ "type": "t_uint256" }, { - "astId": 19525, + "astId": 21519, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "genesisEpoch", "offset": 0, @@ -910,7 +995,7 @@ "type": "t_uint256" }, { - "astId": 19527, + "astId": 21521, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "circSupply", "offset": 0, @@ -918,7 +1003,7 @@ "type": "t_uint256" }, { - "astId": 19529, + "astId": 21523, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "topDownNonce", "offset": 0, @@ -926,7 +1011,7 @@ "type": "t_uint64" }, { - "astId": 19531, + "astId": 21525, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "appliedBottomUpNonce", "offset": 8, @@ -934,22 +1019,22 @@ "type": "t_uint64" }, { - "astId": 19534, + "astId": 21528, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "id", "offset": 0, "slot": "4", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" } ], "numberOfBytes": "192" }, - "t_struct(SubnetID)19520_storage": { + "t_struct(SubnetID)21514_storage": { "encoding": "inplace", "label": "struct SubnetID", "members": [ { - "astId": 19515, + "astId": 21509, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "root", "offset": 0, @@ -957,7 +1042,7 @@ "type": "t_uint64" }, { - "astId": 19519, + "astId": 21513, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "route", "offset": 0, @@ -967,27 +1052,27 @@ ], "numberOfBytes": "64" }, - "t_struct(UintSet)3616_storage": { + "t_struct(UintSet)4363_storage": { "encoding": "inplace", "label": "struct EnumerableSet.UintSet", "members": [ { - "astId": 3615, + "astId": 4362, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" } ], "numberOfBytes": "64" }, - "t_struct(Validator)19672_storage": { + "t_struct(Validator)21666_storage": { "encoding": "inplace", "label": "struct Validator", "members": [ { - "astId": 19667, + "astId": 21661, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "weight", "offset": 0, @@ -995,7 +1080,7 @@ "type": "t_uint256" }, { - "astId": 19669, + "astId": 21663, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "addr", "offset": 0, @@ -1003,7 +1088,7 @@ "type": "t_address" }, { - "astId": 19671, + "astId": 21665, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "metadata", "offset": 0, @@ -1013,12 +1098,12 @@ ], "numberOfBytes": "96" }, - "t_struct(ValidatorInfo)19613_storage": { + "t_struct(ValidatorInfo)21607_storage": { "encoding": "inplace", "label": "struct ValidatorInfo", "members": [ { - "astId": 19605, + "astId": 21599, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "federatedPower", "offset": 0, @@ -1026,7 +1111,7 @@ "type": "t_uint256" }, { - "astId": 19607, + "astId": 21601, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "confirmedCollateral", "offset": 0, @@ -1034,7 +1119,7 @@ "type": "t_uint256" }, { - "astId": 19609, + "astId": 21603, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "totalCollateral", "offset": 0, @@ -1042,7 +1127,7 @@ "type": "t_uint256" }, { - "astId": 19612, + "astId": 21606, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "metadata", "offset": 0, @@ -1052,20 +1137,20 @@ ], "numberOfBytes": "128" }, - "t_struct(ValidatorSet)19648_storage": { + "t_struct(ValidatorSet)21642_storage": { "encoding": "inplace", "label": "struct ValidatorSet", "members": [ { - "astId": 19627, + "astId": 21621, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "permissionMode", "offset": 0, "slot": "0", - "type": "t_enum(PermissionMode)19618" + "type": "t_enum(PermissionMode)21612" }, { - "astId": 19630, + "astId": 21624, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "activeLimit", "offset": 1, @@ -1073,7 +1158,7 @@ "type": "t_uint16" }, { - "astId": 19633, + "astId": 21627, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "totalConfirmedCollateral", "offset": 0, @@ -1081,28 +1166,28 @@ "type": "t_uint256" }, { - "astId": 19639, + "astId": 21633, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "validators", "offset": 0, "slot": "2", - "type": "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)" + "type": "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)" }, { - "astId": 19643, + "astId": 21637, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "activeValidators", "offset": 0, "slot": "3", - "type": "t_struct(MinPQ)17670_storage" + "type": "t_struct(MinPQ)20370_storage" }, { - "astId": 19647, + "astId": 21641, "contract": "contracts/GatewayDiamond.sol:GatewayDiamond", "label": "waitingValidators", "offset": 0, "slot": "6", - "type": "t_struct(MaxPQ)17052_storage" + "type": "t_struct(MaxPQ)19752_storage" } ], "numberOfBytes": "288" @@ -1126,6 +1211,11 @@ "encoding": "inplace", "label": "uint8", "numberOfBytes": "1" + }, + "t_userDefinedValueType(MerkleHash)21265": { + "encoding": "inplace", + "label": "Consensus.MerkleHash", + "numberOfBytes": "32" } } } diff --git a/contracts/.storage-layouts/SubnetActorDiamond.json b/contracts/.storage-layouts/SubnetActorDiamond.json index 0d89b7492..673c708f7 100644 --- a/contracts/.storage-layouts/SubnetActorDiamond.json +++ b/contracts/.storage-layouts/SubnetActorDiamond.json @@ -1,12 +1,12 @@ { "storage": [ { - "astId": 4144, + "astId": 4893, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "s", "offset": 0, "slot": "0", - "type": "t_struct(SubnetActorStorage)16306_storage" + "type": "t_struct(SubnetActorStorage)18983_storage" } ], "types": { @@ -27,14 +27,14 @@ "label": "bytes32[]", "numberOfBytes": "32" }, - "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage": { - "base": "t_struct(IpcEnvelope)19408_storage", + "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage": { + "base": "t_struct(IpcEnvelope)21402_storage", "encoding": "dynamic_array", "label": "struct IpcEnvelope[]", "numberOfBytes": "32" }, - "t_array(t_struct(Validator)19672_storage)dyn_storage": { - "base": "t_struct(Validator)19672_storage", + "t_array(t_struct(Validator)21666_storage)dyn_storage": { + "base": "t_struct(Validator)21666_storage", "encoding": "dynamic_array", "label": "struct Validator[]", "numberOfBytes": "32" @@ -54,27 +54,27 @@ "label": "bytes", "numberOfBytes": "32" }, - "t_enum(AssetKind)19693": { + "t_enum(AssetKind)21687": { "encoding": "inplace", "label": "enum AssetKind", "numberOfBytes": "1" }, - "t_enum(ConsensusType)5500": { + "t_enum(ConsensusType)6298": { "encoding": "inplace", "label": "enum ConsensusType", "numberOfBytes": "1" }, - "t_enum(IpcMsgKind)19385": { + "t_enum(IpcMsgKind)21376": { "encoding": "inplace", "label": "enum IpcMsgKind", "numberOfBytes": "1" }, - "t_enum(PermissionMode)19618": { + "t_enum(PermissionMode)21612": { "encoding": "inplace", "label": "enum PermissionMode", "numberOfBytes": "1" }, - "t_enum(StakingOperation)19541": { + "t_enum(StakingOperation)21535": { "encoding": "inplace", "label": "enum StakingOperation", "numberOfBytes": "1" @@ -91,19 +91,19 @@ "numberOfBytes": "32", "value": "t_string_storage" }, - "t_mapping(t_address,t_struct(AddressStakingReleases)19590_storage)": { + "t_mapping(t_address,t_struct(AddressStakingReleases)21584_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct AddressStakingReleases)", "numberOfBytes": "32", - "value": "t_struct(AddressStakingReleases)19590_storage" + "value": "t_struct(AddressStakingReleases)21584_storage" }, - "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)": { + "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct ValidatorInfo)", "numberOfBytes": "32", - "value": "t_struct(ValidatorInfo)19613_storage" + "value": "t_struct(ValidatorInfo)21607_storage" }, "t_mapping(t_address,t_uint16)": { "encoding": "mapping", @@ -133,53 +133,53 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_uint16,t_struct(StakingRelease)19579_storage)": { + "t_mapping(t_uint16,t_struct(StakingRelease)21573_storage)": { "encoding": "mapping", "key": "t_uint16", "label": "mapping(uint16 => struct StakingRelease)", "numberOfBytes": "32", - "value": "t_struct(StakingRelease)19579_storage" + "value": "t_struct(StakingRelease)21573_storage" }, - "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)": { + "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct BottomUpCheckpoint)", "numberOfBytes": "32", - "value": "t_struct(BottomUpCheckpoint)19331_storage" + "value": "t_struct(BottomUpCheckpoint)21351_storage" }, - "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)": { + "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)": { "encoding": "mapping", "key": "t_uint64", "label": "mapping(uint64 => struct StakingChange)", "numberOfBytes": "32", - "value": "t_struct(StakingChange)19550_storage" + "value": "t_struct(StakingChange)21544_storage" }, "t_string_storage": { "encoding": "bytes", "label": "string", "numberOfBytes": "32" }, - "t_struct(AddressSet)3459_storage": { + "t_struct(AddressSet)4206_storage": { "encoding": "inplace", "label": "struct EnumerableSet.AddressSet", "members": [ { - "astId": 3458, + "astId": 4205, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" } ], "numberOfBytes": "64" }, - "t_struct(AddressStakingReleases)19590_storage": { + "t_struct(AddressStakingReleases)21584_storage": { "encoding": "inplace", "label": "struct AddressStakingReleases", "members": [ { - "astId": 19582, + "astId": 21576, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "length", "offset": 0, @@ -187,7 +187,7 @@ "type": "t_uint16" }, { - "astId": 19584, + "astId": 21578, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "startIdx", "offset": 2, @@ -195,30 +195,53 @@ "type": "t_uint16" }, { - "astId": 19589, + "astId": 21583, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "releases", "offset": 0, "slot": "1", - "type": "t_mapping(t_uint16,t_struct(StakingRelease)19579_storage)" + "type": "t_mapping(t_uint16,t_struct(StakingRelease)21573_storage)" } ], "numberOfBytes": "64" }, - "t_struct(Asset)19689_storage": { + "t_struct(AggregatedStats)21272_storage": { + "encoding": "inplace", + "label": "struct Consensus.AggregatedStats", + "members": [ + { + "astId": 21268, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "totalActiveValidators", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 21271, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "totalNumBlocksCommitted", + "offset": 8, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Asset)21683_storage": { "encoding": "inplace", "label": "struct Asset", "members": [ { - "astId": 19685, + "astId": 21679, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "kind", "offset": 0, "slot": "0", - "type": "t_enum(AssetKind)19693" + "type": "t_enum(AssetKind)21687" }, { - "astId": 19688, + "astId": 21682, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "tokenAddress", "offset": 1, @@ -228,20 +251,20 @@ ], "numberOfBytes": "32" }, - "t_struct(BottomUpCheckpoint)19331_storage": { + "t_struct(BottomUpCheckpoint)21351_storage": { "encoding": "inplace", "label": "struct BottomUpCheckpoint", "members": [ { - "astId": 19316, + "astId": 21332, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "subnetID", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19319, + "astId": 21335, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "blockHeight", "offset": 0, @@ -249,7 +272,7 @@ "type": "t_uint256" }, { - "astId": 19322, + "astId": 21338, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "blockHash", "offset": 0, @@ -257,7 +280,7 @@ "type": "t_bytes32" }, { - "astId": 19325, + "astId": 21341, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "nextConfigurationNumber", "offset": 0, @@ -265,22 +288,68 @@ "type": "t_uint64" }, { - "astId": 19330, + "astId": 21346, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "msgs", "offset": 0, "slot": "5", - "type": "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage" + "type": "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage" + }, + { + "astId": 21350, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "activity", + "offset": 0, + "slot": "6", + "type": "t_struct(CompressedActivityRollup)21262_storage" + } + ], + "numberOfBytes": "256" + }, + "t_struct(CompressedActivityRollup)21262_storage": { + "encoding": "inplace", + "label": "struct CompressedActivityRollup", + "members": [ + { + "astId": 21261, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "consensus", + "offset": 0, + "slot": "0", + "type": "t_struct(CompressedSummary)21289_storage" + } + ], + "numberOfBytes": "64" + }, + "t_struct(CompressedSummary)21289_storage": { + "encoding": "inplace", + "label": "struct Consensus.CompressedSummary", + "members": [ + { + "astId": 21284, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "stats", + "offset": 0, + "slot": "0", + "type": "t_struct(AggregatedStats)21272_storage" + }, + { + "astId": 21288, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "dataRootCommitment", + "offset": 0, + "slot": "1", + "type": "t_userDefinedValueType(MerkleHash)21265" } ], - "numberOfBytes": "192" + "numberOfBytes": "64" }, - "t_struct(FvmAddress)19439_storage": { + "t_struct(FvmAddress)21433_storage": { "encoding": "inplace", "label": "struct FvmAddress", "members": [ { - "astId": 19436, + "astId": 21430, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "addrType", "offset": 0, @@ -288,7 +357,7 @@ "type": "t_uint8" }, { - "astId": 19438, + "astId": 21432, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "payload", "offset": 0, @@ -298,67 +367,67 @@ ], "numberOfBytes": "64" }, - "t_struct(IPCAddress)19664_storage": { + "t_struct(IPCAddress)21658_storage": { "encoding": "inplace", "label": "struct IPCAddress", "members": [ { - "astId": 19660, + "astId": 21654, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "subnetId", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19663, + "astId": 21657, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "rawAddress", "offset": 0, "slot": "2", - "type": "t_struct(FvmAddress)19439_storage" + "type": "t_struct(FvmAddress)21433_storage" } ], "numberOfBytes": "128" }, - "t_struct(IpcEnvelope)19408_storage": { + "t_struct(IpcEnvelope)21402_storage": { "encoding": "inplace", "label": "struct IpcEnvelope", "members": [ { - "astId": 19390, + "astId": 21381, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "kind", "offset": 0, "slot": "0", - "type": "t_enum(IpcMsgKind)19385" + "type": "t_enum(IpcMsgKind)21376" }, { - "astId": 19394, + "astId": 21385, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "to", "offset": 0, "slot": "1", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19398, + "astId": 21389, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "from", "offset": 0, "slot": "5", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19401, + "astId": 21392, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", - "label": "nonce", + "label": "localNonce", "offset": 0, "slot": "9", "type": "t_uint64" }, { - "astId": 19404, + "astId": 21395, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "value", "offset": 0, @@ -366,52 +435,60 @@ "type": "t_uint256" }, { - "astId": 19407, + "astId": 21398, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "message", "offset": 0, "slot": "11", "type": "t_bytes_storage" + }, + { + "astId": 21401, + "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", + "label": "originalNonce", + "offset": 0, + "slot": "12", + "type": "t_uint64" } ], - "numberOfBytes": "384" + "numberOfBytes": "416" }, - "t_struct(MaxPQ)17052_storage": { + "t_struct(MaxPQ)19752_storage": { "encoding": "inplace", "label": "struct MaxPQ", "members": [ { - "astId": 17051, + "astId": 19751, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(MinPQ)17670_storage": { + "t_struct(MinPQ)20370_storage": { "encoding": "inplace", "label": "struct MinPQ", "members": [ { - "astId": 17669, + "astId": 20369, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(PQ)18300_storage": { + "t_struct(PQ)21000_storage": { "encoding": "inplace", "label": "struct PQ", "members": [ { - "astId": 18289, + "astId": 20989, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "size", "offset": 0, @@ -419,7 +496,7 @@ "type": "t_uint16" }, { - "astId": 18294, + "astId": 20994, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "addressToPos", "offset": 0, @@ -427,7 +504,7 @@ "type": "t_mapping(t_address,t_uint16)" }, { - "astId": 18299, + "astId": 20999, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "posToAddress", "offset": 0, @@ -437,12 +514,12 @@ ], "numberOfBytes": "96" }, - "t_struct(Set)3144_storage": { + "t_struct(Set)3891_storage": { "encoding": "inplace", "label": "struct EnumerableSet.Set", "members": [ { - "astId": 3139, + "astId": 3886, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "_values", "offset": 0, @@ -450,7 +527,7 @@ "type": "t_array(t_bytes32)dyn_storage" }, { - "astId": 3143, + "astId": 3890, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "_positions", "offset": 0, @@ -460,20 +537,20 @@ ], "numberOfBytes": "64" }, - "t_struct(StakingChange)19550_storage": { + "t_struct(StakingChange)21544_storage": { "encoding": "inplace", "label": "struct StakingChange", "members": [ { - "astId": 19545, + "astId": 21539, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "op", "offset": 0, "slot": "0", - "type": "t_enum(StakingOperation)19541" + "type": "t_enum(StakingOperation)21535" }, { - "astId": 19547, + "astId": 21541, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "payload", "offset": 0, @@ -481,7 +558,7 @@ "type": "t_bytes_storage" }, { - "astId": 19549, + "astId": 21543, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "validator", "offset": 0, @@ -491,12 +568,12 @@ ], "numberOfBytes": "96" }, - "t_struct(StakingChangeLog)19571_storage": { + "t_struct(StakingChangeLog)21565_storage": { "encoding": "inplace", "label": "struct StakingChangeLog", "members": [ { - "astId": 19561, + "astId": 21555, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "nextConfigurationNumber", "offset": 0, @@ -504,7 +581,7 @@ "type": "t_uint64" }, { - "astId": 19564, + "astId": 21558, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "startConfigurationNumber", "offset": 8, @@ -512,22 +589,22 @@ "type": "t_uint64" }, { - "astId": 19570, + "astId": 21564, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "changes", "offset": 0, "slot": "1", - "type": "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)" + "type": "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)" } ], "numberOfBytes": "64" }, - "t_struct(StakingRelease)19579_storage": { + "t_struct(StakingRelease)21573_storage": { "encoding": "inplace", "label": "struct StakingRelease", "members": [ { - "astId": 19575, + "astId": 21569, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "releaseAt", "offset": 0, @@ -535,7 +612,7 @@ "type": "t_uint256" }, { - "astId": 19578, + "astId": 21572, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "amount", "offset": 0, @@ -545,12 +622,12 @@ ], "numberOfBytes": "64" }, - "t_struct(StakingReleaseQueue)19601_storage": { + "t_struct(StakingReleaseQueue)21595_storage": { "encoding": "inplace", "label": "struct StakingReleaseQueue", "members": [ { - "astId": 19594, + "astId": 21588, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "lockingDuration", "offset": 0, @@ -558,22 +635,22 @@ "type": "t_uint256" }, { - "astId": 19600, + "astId": 21594, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "releases", "offset": 0, "slot": "1", - "type": "t_mapping(t_address,t_struct(AddressStakingReleases)19590_storage)" + "type": "t_mapping(t_address,t_struct(AddressStakingReleases)21584_storage)" } ], "numberOfBytes": "64" }, - "t_struct(SubnetActorStorage)16306_storage": { + "t_struct(SubnetActorStorage)18983_storage": { "encoding": "inplace", "label": "struct SubnetActorStorage", "members": [ { - "astId": 16213, + "astId": 18890, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "genesisCircSupply", "offset": 0, @@ -581,7 +658,7 @@ "type": "t_uint256" }, { - "astId": 16216, + "astId": 18893, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "lastBottomUpCheckpointHeight", "offset": 0, @@ -589,7 +666,7 @@ "type": "t_uint256" }, { - "astId": 16219, + "astId": 18896, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "minActivationCollateral", "offset": 0, @@ -597,7 +674,7 @@ "type": "t_uint256" }, { - "astId": 16222, + "astId": 18899, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "bottomUpCheckPeriod", "offset": 0, @@ -605,7 +682,7 @@ "type": "t_uint256" }, { - "astId": 16224, + "astId": 18901, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "currentSubnetHash", "offset": 0, @@ -613,7 +690,7 @@ "type": "t_bytes32" }, { - "astId": 16227, + "astId": 18904, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "ipcGatewayAddr", "offset": 0, @@ -621,7 +698,7 @@ "type": "t_address" }, { - "astId": 16230, + "astId": 18907, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "maxMsgsPerBottomUpBatch", "offset": 20, @@ -629,7 +706,7 @@ "type": "t_uint64" }, { - "astId": 16233, + "astId": 18910, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "majorityPercentage", "offset": 28, @@ -637,7 +714,7 @@ "type": "t_uint8" }, { - "astId": 16236, + "astId": 18913, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "powerScale", "offset": 29, @@ -645,15 +722,15 @@ "type": "t_int8" }, { - "astId": 16240, + "astId": 18917, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "consensus", "offset": 30, "slot": "5", - "type": "t_enum(ConsensusType)5500" + "type": "t_enum(ConsensusType)6298" }, { - "astId": 16243, + "astId": 18920, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "bootstrapped", "offset": 31, @@ -661,7 +738,7 @@ "type": "t_bool" }, { - "astId": 16246, + "astId": 18923, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "minValidators", "offset": 0, @@ -669,7 +746,7 @@ "type": "t_uint64" }, { - "astId": 16249, + "astId": 18926, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "killed", "offset": 8, @@ -677,55 +754,55 @@ "type": "t_bool" }, { - "astId": 16253, + "astId": 18930, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "supplySource", "offset": 0, "slot": "7", - "type": "t_struct(Asset)19689_storage" + "type": "t_struct(Asset)21683_storage" }, { - "astId": 16257, + "astId": 18934, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "collateralSource", "offset": 0, "slot": "8", - "type": "t_struct(Asset)19689_storage" + "type": "t_struct(Asset)21683_storage" }, { - "astId": 16261, + "astId": 18938, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "parentId", "offset": 0, "slot": "9", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 16265, + "astId": 18942, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "validatorSet", "offset": 0, "slot": "11", - "type": "t_struct(ValidatorSet)19648_storage" + "type": "t_struct(ValidatorSet)21642_storage" }, { - "astId": 16269, + "astId": 18946, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "changeSet", "offset": 0, "slot": "20", - "type": "t_struct(StakingChangeLog)19571_storage" + "type": "t_struct(StakingChangeLog)21565_storage" }, { - "astId": 16273, + "astId": 18950, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "releaseQueue", "offset": 0, "slot": "22", - "type": "t_struct(StakingReleaseQueue)19601_storage" + "type": "t_struct(StakingReleaseQueue)21595_storage" }, { - "astId": 16278, + "astId": 18955, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "bootstrapNodes", "offset": 0, @@ -733,31 +810,31 @@ "type": "t_mapping(t_address,t_string_storage)" }, { - "astId": 16282, + "astId": 18959, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "bootstrapOwners", "offset": 0, "slot": "25", - "type": "t_struct(AddressSet)3459_storage" + "type": "t_struct(AddressSet)4206_storage" }, { - "astId": 16288, + "astId": 18965, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "committedCheckpoints", "offset": 0, "slot": "27", - "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)" + "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)" }, { - "astId": 16293, + "astId": 18970, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "genesisValidators", "offset": 0, "slot": "28", - "type": "t_array(t_struct(Validator)19672_storage)dyn_storage" + "type": "t_array(t_struct(Validator)21666_storage)dyn_storage" }, { - "astId": 16298, + "astId": 18975, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "genesisBalance", "offset": 0, @@ -765,7 +842,7 @@ "type": "t_mapping(t_address,t_uint256)" }, { - "astId": 16302, + "astId": 18979, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "genesisBalanceKeys", "offset": 0, @@ -773,7 +850,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 16305, + "astId": 18982, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "validatorGater", "offset": 0, @@ -783,12 +860,12 @@ ], "numberOfBytes": "1024" }, - "t_struct(SubnetID)19520_storage": { + "t_struct(SubnetID)21514_storage": { "encoding": "inplace", "label": "struct SubnetID", "members": [ { - "astId": 19515, + "astId": 21509, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "root", "offset": 0, @@ -796,7 +873,7 @@ "type": "t_uint64" }, { - "astId": 19519, + "astId": 21513, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "route", "offset": 0, @@ -806,12 +883,12 @@ ], "numberOfBytes": "64" }, - "t_struct(Validator)19672_storage": { + "t_struct(Validator)21666_storage": { "encoding": "inplace", "label": "struct Validator", "members": [ { - "astId": 19667, + "astId": 21661, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "weight", "offset": 0, @@ -819,7 +896,7 @@ "type": "t_uint256" }, { - "astId": 19669, + "astId": 21663, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "addr", "offset": 0, @@ -827,7 +904,7 @@ "type": "t_address" }, { - "astId": 19671, + "astId": 21665, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "metadata", "offset": 0, @@ -837,12 +914,12 @@ ], "numberOfBytes": "96" }, - "t_struct(ValidatorInfo)19613_storage": { + "t_struct(ValidatorInfo)21607_storage": { "encoding": "inplace", "label": "struct ValidatorInfo", "members": [ { - "astId": 19605, + "astId": 21599, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "federatedPower", "offset": 0, @@ -850,7 +927,7 @@ "type": "t_uint256" }, { - "astId": 19607, + "astId": 21601, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "confirmedCollateral", "offset": 0, @@ -858,7 +935,7 @@ "type": "t_uint256" }, { - "astId": 19609, + "astId": 21603, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "totalCollateral", "offset": 0, @@ -866,7 +943,7 @@ "type": "t_uint256" }, { - "astId": 19612, + "astId": 21606, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "metadata", "offset": 0, @@ -876,20 +953,20 @@ ], "numberOfBytes": "128" }, - "t_struct(ValidatorSet)19648_storage": { + "t_struct(ValidatorSet)21642_storage": { "encoding": "inplace", "label": "struct ValidatorSet", "members": [ { - "astId": 19627, + "astId": 21621, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "permissionMode", "offset": 0, "slot": "0", - "type": "t_enum(PermissionMode)19618" + "type": "t_enum(PermissionMode)21612" }, { - "astId": 19630, + "astId": 21624, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "activeLimit", "offset": 1, @@ -897,7 +974,7 @@ "type": "t_uint16" }, { - "astId": 19633, + "astId": 21627, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "totalConfirmedCollateral", "offset": 0, @@ -905,28 +982,28 @@ "type": "t_uint256" }, { - "astId": 19639, + "astId": 21633, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "validators", "offset": 0, "slot": "2", - "type": "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)" + "type": "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)" }, { - "astId": 19643, + "astId": 21637, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "activeValidators", "offset": 0, "slot": "3", - "type": "t_struct(MinPQ)17670_storage" + "type": "t_struct(MinPQ)20370_storage" }, { - "astId": 19647, + "astId": 21641, "contract": "contracts/SubnetActorDiamond.sol:SubnetActorDiamond", "label": "waitingValidators", "offset": 0, "slot": "6", - "type": "t_struct(MaxPQ)17052_storage" + "type": "t_struct(MaxPQ)19752_storage" } ], "numberOfBytes": "288" @@ -950,6 +1027,11 @@ "encoding": "inplace", "label": "uint8", "numberOfBytes": "1" + }, + "t_userDefinedValueType(MerkleHash)21265": { + "encoding": "inplace", + "label": "Consensus.MerkleHash", + "numberOfBytes": "32" } } } diff --git a/contracts/.storage-layouts/SubnetActorModifiers.json b/contracts/.storage-layouts/SubnetActorModifiers.json index baf89be37..37dd48fda 100644 --- a/contracts/.storage-layouts/SubnetActorModifiers.json +++ b/contracts/.storage-layouts/SubnetActorModifiers.json @@ -1,12 +1,12 @@ { "storage": [ { - "astId": 16320, + "astId": 18997, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "s", "offset": 0, "slot": "0", - "type": "t_struct(SubnetActorStorage)16306_storage" + "type": "t_struct(SubnetActorStorage)18983_storage" } ], "types": { @@ -27,14 +27,14 @@ "label": "bytes32[]", "numberOfBytes": "32" }, - "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage": { - "base": "t_struct(IpcEnvelope)19408_storage", + "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage": { + "base": "t_struct(IpcEnvelope)21402_storage", "encoding": "dynamic_array", "label": "struct IpcEnvelope[]", "numberOfBytes": "32" }, - "t_array(t_struct(Validator)19672_storage)dyn_storage": { - "base": "t_struct(Validator)19672_storage", + "t_array(t_struct(Validator)21666_storage)dyn_storage": { + "base": "t_struct(Validator)21666_storage", "encoding": "dynamic_array", "label": "struct Validator[]", "numberOfBytes": "32" @@ -54,27 +54,27 @@ "label": "bytes", "numberOfBytes": "32" }, - "t_enum(AssetKind)19693": { + "t_enum(AssetKind)21687": { "encoding": "inplace", "label": "enum AssetKind", "numberOfBytes": "1" }, - "t_enum(ConsensusType)5500": { + "t_enum(ConsensusType)6298": { "encoding": "inplace", "label": "enum ConsensusType", "numberOfBytes": "1" }, - "t_enum(IpcMsgKind)19385": { + "t_enum(IpcMsgKind)21376": { "encoding": "inplace", "label": "enum IpcMsgKind", "numberOfBytes": "1" }, - "t_enum(PermissionMode)19618": { + "t_enum(PermissionMode)21612": { "encoding": "inplace", "label": "enum PermissionMode", "numberOfBytes": "1" }, - "t_enum(StakingOperation)19541": { + "t_enum(StakingOperation)21535": { "encoding": "inplace", "label": "enum StakingOperation", "numberOfBytes": "1" @@ -91,19 +91,19 @@ "numberOfBytes": "32", "value": "t_string_storage" }, - "t_mapping(t_address,t_struct(AddressStakingReleases)19590_storage)": { + "t_mapping(t_address,t_struct(AddressStakingReleases)21584_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct AddressStakingReleases)", "numberOfBytes": "32", - "value": "t_struct(AddressStakingReleases)19590_storage" + "value": "t_struct(AddressStakingReleases)21584_storage" }, - "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)": { + "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => struct ValidatorInfo)", "numberOfBytes": "32", - "value": "t_struct(ValidatorInfo)19613_storage" + "value": "t_struct(ValidatorInfo)21607_storage" }, "t_mapping(t_address,t_uint16)": { "encoding": "mapping", @@ -133,53 +133,53 @@ "numberOfBytes": "32", "value": "t_address" }, - "t_mapping(t_uint16,t_struct(StakingRelease)19579_storage)": { + "t_mapping(t_uint16,t_struct(StakingRelease)21573_storage)": { "encoding": "mapping", "key": "t_uint16", "label": "mapping(uint16 => struct StakingRelease)", "numberOfBytes": "32", - "value": "t_struct(StakingRelease)19579_storage" + "value": "t_struct(StakingRelease)21573_storage" }, - "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)": { + "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)": { "encoding": "mapping", "key": "t_uint256", "label": "mapping(uint256 => struct BottomUpCheckpoint)", "numberOfBytes": "32", - "value": "t_struct(BottomUpCheckpoint)19331_storage" + "value": "t_struct(BottomUpCheckpoint)21351_storage" }, - "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)": { + "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)": { "encoding": "mapping", "key": "t_uint64", "label": "mapping(uint64 => struct StakingChange)", "numberOfBytes": "32", - "value": "t_struct(StakingChange)19550_storage" + "value": "t_struct(StakingChange)21544_storage" }, "t_string_storage": { "encoding": "bytes", "label": "string", "numberOfBytes": "32" }, - "t_struct(AddressSet)3459_storage": { + "t_struct(AddressSet)4206_storage": { "encoding": "inplace", "label": "struct EnumerableSet.AddressSet", "members": [ { - "astId": 3458, + "astId": 4205, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "_inner", "offset": 0, "slot": "0", - "type": "t_struct(Set)3144_storage" + "type": "t_struct(Set)3891_storage" } ], "numberOfBytes": "64" }, - "t_struct(AddressStakingReleases)19590_storage": { + "t_struct(AddressStakingReleases)21584_storage": { "encoding": "inplace", "label": "struct AddressStakingReleases", "members": [ { - "astId": 19582, + "astId": 21576, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "length", "offset": 0, @@ -187,7 +187,7 @@ "type": "t_uint16" }, { - "astId": 19584, + "astId": 21578, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "startIdx", "offset": 2, @@ -195,30 +195,53 @@ "type": "t_uint16" }, { - "astId": 19589, + "astId": 21583, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "releases", "offset": 0, "slot": "1", - "type": "t_mapping(t_uint16,t_struct(StakingRelease)19579_storage)" + "type": "t_mapping(t_uint16,t_struct(StakingRelease)21573_storage)" } ], "numberOfBytes": "64" }, - "t_struct(Asset)19689_storage": { + "t_struct(AggregatedStats)21272_storage": { + "encoding": "inplace", + "label": "struct Consensus.AggregatedStats", + "members": [ + { + "astId": 21268, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "totalActiveValidators", + "offset": 0, + "slot": "0", + "type": "t_uint64" + }, + { + "astId": 21271, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "totalNumBlocksCommitted", + "offset": 8, + "slot": "0", + "type": "t_uint64" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Asset)21683_storage": { "encoding": "inplace", "label": "struct Asset", "members": [ { - "astId": 19685, + "astId": 21679, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "kind", "offset": 0, "slot": "0", - "type": "t_enum(AssetKind)19693" + "type": "t_enum(AssetKind)21687" }, { - "astId": 19688, + "astId": 21682, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "tokenAddress", "offset": 1, @@ -228,20 +251,20 @@ ], "numberOfBytes": "32" }, - "t_struct(BottomUpCheckpoint)19331_storage": { + "t_struct(BottomUpCheckpoint)21351_storage": { "encoding": "inplace", "label": "struct BottomUpCheckpoint", "members": [ { - "astId": 19316, + "astId": 21332, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "subnetID", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19319, + "astId": 21335, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "blockHeight", "offset": 0, @@ -249,7 +272,7 @@ "type": "t_uint256" }, { - "astId": 19322, + "astId": 21338, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "blockHash", "offset": 0, @@ -257,7 +280,7 @@ "type": "t_bytes32" }, { - "astId": 19325, + "astId": 21341, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "nextConfigurationNumber", "offset": 0, @@ -265,22 +288,68 @@ "type": "t_uint64" }, { - "astId": 19330, + "astId": 21346, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "msgs", "offset": 0, "slot": "5", - "type": "t_array(t_struct(IpcEnvelope)19408_storage)dyn_storage" + "type": "t_array(t_struct(IpcEnvelope)21402_storage)dyn_storage" + }, + { + "astId": 21350, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "activity", + "offset": 0, + "slot": "6", + "type": "t_struct(CompressedActivityRollup)21262_storage" + } + ], + "numberOfBytes": "256" + }, + "t_struct(CompressedActivityRollup)21262_storage": { + "encoding": "inplace", + "label": "struct CompressedActivityRollup", + "members": [ + { + "astId": 21261, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "consensus", + "offset": 0, + "slot": "0", + "type": "t_struct(CompressedSummary)21289_storage" + } + ], + "numberOfBytes": "64" + }, + "t_struct(CompressedSummary)21289_storage": { + "encoding": "inplace", + "label": "struct Consensus.CompressedSummary", + "members": [ + { + "astId": 21284, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "stats", + "offset": 0, + "slot": "0", + "type": "t_struct(AggregatedStats)21272_storage" + }, + { + "astId": 21288, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "dataRootCommitment", + "offset": 0, + "slot": "1", + "type": "t_userDefinedValueType(MerkleHash)21265" } ], - "numberOfBytes": "192" + "numberOfBytes": "64" }, - "t_struct(FvmAddress)19439_storage": { + "t_struct(FvmAddress)21433_storage": { "encoding": "inplace", "label": "struct FvmAddress", "members": [ { - "astId": 19436, + "astId": 21430, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "addrType", "offset": 0, @@ -288,7 +357,7 @@ "type": "t_uint8" }, { - "astId": 19438, + "astId": 21432, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "payload", "offset": 0, @@ -298,67 +367,67 @@ ], "numberOfBytes": "64" }, - "t_struct(IPCAddress)19664_storage": { + "t_struct(IPCAddress)21658_storage": { "encoding": "inplace", "label": "struct IPCAddress", "members": [ { - "astId": 19660, + "astId": 21654, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "subnetId", "offset": 0, "slot": "0", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 19663, + "astId": 21657, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "rawAddress", "offset": 0, "slot": "2", - "type": "t_struct(FvmAddress)19439_storage" + "type": "t_struct(FvmAddress)21433_storage" } ], "numberOfBytes": "128" }, - "t_struct(IpcEnvelope)19408_storage": { + "t_struct(IpcEnvelope)21402_storage": { "encoding": "inplace", "label": "struct IpcEnvelope", "members": [ { - "astId": 19390, + "astId": 21381, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "kind", "offset": 0, "slot": "0", - "type": "t_enum(IpcMsgKind)19385" + "type": "t_enum(IpcMsgKind)21376" }, { - "astId": 19394, + "astId": 21385, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "to", "offset": 0, "slot": "1", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19398, + "astId": 21389, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "from", "offset": 0, "slot": "5", - "type": "t_struct(IPCAddress)19664_storage" + "type": "t_struct(IPCAddress)21658_storage" }, { - "astId": 19401, + "astId": 21392, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", - "label": "nonce", + "label": "localNonce", "offset": 0, "slot": "9", "type": "t_uint64" }, { - "astId": 19404, + "astId": 21395, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "value", "offset": 0, @@ -366,52 +435,60 @@ "type": "t_uint256" }, { - "astId": 19407, + "astId": 21398, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "message", "offset": 0, "slot": "11", "type": "t_bytes_storage" + }, + { + "astId": 21401, + "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", + "label": "originalNonce", + "offset": 0, + "slot": "12", + "type": "t_uint64" } ], - "numberOfBytes": "384" + "numberOfBytes": "416" }, - "t_struct(MaxPQ)17052_storage": { + "t_struct(MaxPQ)19752_storage": { "encoding": "inplace", "label": "struct MaxPQ", "members": [ { - "astId": 17051, + "astId": 19751, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(MinPQ)17670_storage": { + "t_struct(MinPQ)20370_storage": { "encoding": "inplace", "label": "struct MinPQ", "members": [ { - "astId": 17669, + "astId": 20369, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "inner", "offset": 0, "slot": "0", - "type": "t_struct(PQ)18300_storage" + "type": "t_struct(PQ)21000_storage" } ], "numberOfBytes": "96" }, - "t_struct(PQ)18300_storage": { + "t_struct(PQ)21000_storage": { "encoding": "inplace", "label": "struct PQ", "members": [ { - "astId": 18289, + "astId": 20989, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "size", "offset": 0, @@ -419,7 +496,7 @@ "type": "t_uint16" }, { - "astId": 18294, + "astId": 20994, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "addressToPos", "offset": 0, @@ -427,7 +504,7 @@ "type": "t_mapping(t_address,t_uint16)" }, { - "astId": 18299, + "astId": 20999, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "posToAddress", "offset": 0, @@ -437,12 +514,12 @@ ], "numberOfBytes": "96" }, - "t_struct(Set)3144_storage": { + "t_struct(Set)3891_storage": { "encoding": "inplace", "label": "struct EnumerableSet.Set", "members": [ { - "astId": 3139, + "astId": 3886, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "_values", "offset": 0, @@ -450,7 +527,7 @@ "type": "t_array(t_bytes32)dyn_storage" }, { - "astId": 3143, + "astId": 3890, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "_positions", "offset": 0, @@ -460,20 +537,20 @@ ], "numberOfBytes": "64" }, - "t_struct(StakingChange)19550_storage": { + "t_struct(StakingChange)21544_storage": { "encoding": "inplace", "label": "struct StakingChange", "members": [ { - "astId": 19545, + "astId": 21539, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "op", "offset": 0, "slot": "0", - "type": "t_enum(StakingOperation)19541" + "type": "t_enum(StakingOperation)21535" }, { - "astId": 19547, + "astId": 21541, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "payload", "offset": 0, @@ -481,7 +558,7 @@ "type": "t_bytes_storage" }, { - "astId": 19549, + "astId": 21543, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "validator", "offset": 0, @@ -491,12 +568,12 @@ ], "numberOfBytes": "96" }, - "t_struct(StakingChangeLog)19571_storage": { + "t_struct(StakingChangeLog)21565_storage": { "encoding": "inplace", "label": "struct StakingChangeLog", "members": [ { - "astId": 19561, + "astId": 21555, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "nextConfigurationNumber", "offset": 0, @@ -504,7 +581,7 @@ "type": "t_uint64" }, { - "astId": 19564, + "astId": 21558, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "startConfigurationNumber", "offset": 8, @@ -512,22 +589,22 @@ "type": "t_uint64" }, { - "astId": 19570, + "astId": 21564, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "changes", "offset": 0, "slot": "1", - "type": "t_mapping(t_uint64,t_struct(StakingChange)19550_storage)" + "type": "t_mapping(t_uint64,t_struct(StakingChange)21544_storage)" } ], "numberOfBytes": "64" }, - "t_struct(StakingRelease)19579_storage": { + "t_struct(StakingRelease)21573_storage": { "encoding": "inplace", "label": "struct StakingRelease", "members": [ { - "astId": 19575, + "astId": 21569, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "releaseAt", "offset": 0, @@ -535,7 +612,7 @@ "type": "t_uint256" }, { - "astId": 19578, + "astId": 21572, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "amount", "offset": 0, @@ -545,12 +622,12 @@ ], "numberOfBytes": "64" }, - "t_struct(StakingReleaseQueue)19601_storage": { + "t_struct(StakingReleaseQueue)21595_storage": { "encoding": "inplace", "label": "struct StakingReleaseQueue", "members": [ { - "astId": 19594, + "astId": 21588, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "lockingDuration", "offset": 0, @@ -558,22 +635,22 @@ "type": "t_uint256" }, { - "astId": 19600, + "astId": 21594, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "releases", "offset": 0, "slot": "1", - "type": "t_mapping(t_address,t_struct(AddressStakingReleases)19590_storage)" + "type": "t_mapping(t_address,t_struct(AddressStakingReleases)21584_storage)" } ], "numberOfBytes": "64" }, - "t_struct(SubnetActorStorage)16306_storage": { + "t_struct(SubnetActorStorage)18983_storage": { "encoding": "inplace", "label": "struct SubnetActorStorage", "members": [ { - "astId": 16213, + "astId": 18890, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "genesisCircSupply", "offset": 0, @@ -581,7 +658,7 @@ "type": "t_uint256" }, { - "astId": 16216, + "astId": 18893, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "lastBottomUpCheckpointHeight", "offset": 0, @@ -589,7 +666,7 @@ "type": "t_uint256" }, { - "astId": 16219, + "astId": 18896, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "minActivationCollateral", "offset": 0, @@ -597,7 +674,7 @@ "type": "t_uint256" }, { - "astId": 16222, + "astId": 18899, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "bottomUpCheckPeriod", "offset": 0, @@ -605,7 +682,7 @@ "type": "t_uint256" }, { - "astId": 16224, + "astId": 18901, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "currentSubnetHash", "offset": 0, @@ -613,7 +690,7 @@ "type": "t_bytes32" }, { - "astId": 16227, + "astId": 18904, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "ipcGatewayAddr", "offset": 0, @@ -621,7 +698,7 @@ "type": "t_address" }, { - "astId": 16230, + "astId": 18907, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "maxMsgsPerBottomUpBatch", "offset": 20, @@ -629,7 +706,7 @@ "type": "t_uint64" }, { - "astId": 16233, + "astId": 18910, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "majorityPercentage", "offset": 28, @@ -637,7 +714,7 @@ "type": "t_uint8" }, { - "astId": 16236, + "astId": 18913, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "powerScale", "offset": 29, @@ -645,15 +722,15 @@ "type": "t_int8" }, { - "astId": 16240, + "astId": 18917, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "consensus", "offset": 30, "slot": "5", - "type": "t_enum(ConsensusType)5500" + "type": "t_enum(ConsensusType)6298" }, { - "astId": 16243, + "astId": 18920, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "bootstrapped", "offset": 31, @@ -661,7 +738,7 @@ "type": "t_bool" }, { - "astId": 16246, + "astId": 18923, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "minValidators", "offset": 0, @@ -669,7 +746,7 @@ "type": "t_uint64" }, { - "astId": 16249, + "astId": 18926, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "killed", "offset": 8, @@ -677,55 +754,55 @@ "type": "t_bool" }, { - "astId": 16253, + "astId": 18930, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "supplySource", "offset": 0, "slot": "7", - "type": "t_struct(Asset)19689_storage" + "type": "t_struct(Asset)21683_storage" }, { - "astId": 16257, + "astId": 18934, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "collateralSource", "offset": 0, "slot": "8", - "type": "t_struct(Asset)19689_storage" + "type": "t_struct(Asset)21683_storage" }, { - "astId": 16261, + "astId": 18938, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "parentId", "offset": 0, "slot": "9", - "type": "t_struct(SubnetID)19520_storage" + "type": "t_struct(SubnetID)21514_storage" }, { - "astId": 16265, + "astId": 18942, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "validatorSet", "offset": 0, "slot": "11", - "type": "t_struct(ValidatorSet)19648_storage" + "type": "t_struct(ValidatorSet)21642_storage" }, { - "astId": 16269, + "astId": 18946, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "changeSet", "offset": 0, "slot": "20", - "type": "t_struct(StakingChangeLog)19571_storage" + "type": "t_struct(StakingChangeLog)21565_storage" }, { - "astId": 16273, + "astId": 18950, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "releaseQueue", "offset": 0, "slot": "22", - "type": "t_struct(StakingReleaseQueue)19601_storage" + "type": "t_struct(StakingReleaseQueue)21595_storage" }, { - "astId": 16278, + "astId": 18955, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "bootstrapNodes", "offset": 0, @@ -733,31 +810,31 @@ "type": "t_mapping(t_address,t_string_storage)" }, { - "astId": 16282, + "astId": 18959, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "bootstrapOwners", "offset": 0, "slot": "25", - "type": "t_struct(AddressSet)3459_storage" + "type": "t_struct(AddressSet)4206_storage" }, { - "astId": 16288, + "astId": 18965, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "committedCheckpoints", "offset": 0, "slot": "27", - "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)19331_storage)" + "type": "t_mapping(t_uint256,t_struct(BottomUpCheckpoint)21351_storage)" }, { - "astId": 16293, + "astId": 18970, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "genesisValidators", "offset": 0, "slot": "28", - "type": "t_array(t_struct(Validator)19672_storage)dyn_storage" + "type": "t_array(t_struct(Validator)21666_storage)dyn_storage" }, { - "astId": 16298, + "astId": 18975, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "genesisBalance", "offset": 0, @@ -765,7 +842,7 @@ "type": "t_mapping(t_address,t_uint256)" }, { - "astId": 16302, + "astId": 18979, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "genesisBalanceKeys", "offset": 0, @@ -773,7 +850,7 @@ "type": "t_array(t_address)dyn_storage" }, { - "astId": 16305, + "astId": 18982, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "validatorGater", "offset": 0, @@ -783,12 +860,12 @@ ], "numberOfBytes": "1024" }, - "t_struct(SubnetID)19520_storage": { + "t_struct(SubnetID)21514_storage": { "encoding": "inplace", "label": "struct SubnetID", "members": [ { - "astId": 19515, + "astId": 21509, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "root", "offset": 0, @@ -796,7 +873,7 @@ "type": "t_uint64" }, { - "astId": 19519, + "astId": 21513, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "route", "offset": 0, @@ -806,12 +883,12 @@ ], "numberOfBytes": "64" }, - "t_struct(Validator)19672_storage": { + "t_struct(Validator)21666_storage": { "encoding": "inplace", "label": "struct Validator", "members": [ { - "astId": 19667, + "astId": 21661, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "weight", "offset": 0, @@ -819,7 +896,7 @@ "type": "t_uint256" }, { - "astId": 19669, + "astId": 21663, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "addr", "offset": 0, @@ -827,7 +904,7 @@ "type": "t_address" }, { - "astId": 19671, + "astId": 21665, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "metadata", "offset": 0, @@ -837,12 +914,12 @@ ], "numberOfBytes": "96" }, - "t_struct(ValidatorInfo)19613_storage": { + "t_struct(ValidatorInfo)21607_storage": { "encoding": "inplace", "label": "struct ValidatorInfo", "members": [ { - "astId": 19605, + "astId": 21599, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "federatedPower", "offset": 0, @@ -850,7 +927,7 @@ "type": "t_uint256" }, { - "astId": 19607, + "astId": 21601, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "confirmedCollateral", "offset": 0, @@ -858,7 +935,7 @@ "type": "t_uint256" }, { - "astId": 19609, + "astId": 21603, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "totalCollateral", "offset": 0, @@ -866,7 +943,7 @@ "type": "t_uint256" }, { - "astId": 19612, + "astId": 21606, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "metadata", "offset": 0, @@ -876,20 +953,20 @@ ], "numberOfBytes": "128" }, - "t_struct(ValidatorSet)19648_storage": { + "t_struct(ValidatorSet)21642_storage": { "encoding": "inplace", "label": "struct ValidatorSet", "members": [ { - "astId": 19627, + "astId": 21621, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "permissionMode", "offset": 0, "slot": "0", - "type": "t_enum(PermissionMode)19618" + "type": "t_enum(PermissionMode)21612" }, { - "astId": 19630, + "astId": 21624, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "activeLimit", "offset": 1, @@ -897,7 +974,7 @@ "type": "t_uint16" }, { - "astId": 19633, + "astId": 21627, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "totalConfirmedCollateral", "offset": 0, @@ -905,28 +982,28 @@ "type": "t_uint256" }, { - "astId": 19639, + "astId": 21633, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "validators", "offset": 0, "slot": "2", - "type": "t_mapping(t_address,t_struct(ValidatorInfo)19613_storage)" + "type": "t_mapping(t_address,t_struct(ValidatorInfo)21607_storage)" }, { - "astId": 19643, + "astId": 21637, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "activeValidators", "offset": 0, "slot": "3", - "type": "t_struct(MinPQ)17670_storage" + "type": "t_struct(MinPQ)20370_storage" }, { - "astId": 19647, + "astId": 21641, "contract": "contracts/lib/LibSubnetActorStorage.sol:SubnetActorModifiers", "label": "waitingValidators", "offset": 0, "slot": "6", - "type": "t_struct(MaxPQ)17052_storage" + "type": "t_struct(MaxPQ)19752_storage" } ], "numberOfBytes": "288" @@ -950,6 +1027,11 @@ "encoding": "inplace", "label": "uint8", "numberOfBytes": "1" + }, + "t_userDefinedValueType(MerkleHash)21265": { + "encoding": "inplace", + "label": "Consensus.MerkleHash", + "numberOfBytes": "32" } } } diff --git a/contracts/contracts/GatewayDiamond.sol b/contracts/contracts/GatewayDiamond.sol index 9a87be704..3d64c3ab2 100644 --- a/contracts/contracts/GatewayDiamond.sol +++ b/contracts/contracts/GatewayDiamond.sol @@ -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; diff --git a/contracts/contracts/errors/IPCErrors.sol b/contracts/contracts/errors/IPCErrors.sol index 7d73a8df4..78ae64654 100644 --- a/contracts/contracts/errors/IPCErrors.sol +++ b/contracts/contracts/errors/IPCErrors.sol @@ -6,7 +6,6 @@ error AlreadyRegisteredSubnet(); error AlreadyInSet(); error CannotConfirmFutureChanges(); error CannotReleaseZero(); -error CannotSendCrossMsgToItself(); error CheckpointAlreadyExists(); error BatchAlreadyExists(); error MaxMsgsPerBatchExceeded(); @@ -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"; diff --git a/contracts/contracts/examples/CrossMessengerCaller.sol b/contracts/contracts/examples/CrossMessengerCaller.sol new file mode 100644 index 000000000..fb98f312f --- /dev/null +++ b/contracts/contracts/examples/CrossMessengerCaller.sol @@ -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); + } +} diff --git a/contracts/contracts/gateway/GatewayGetterFacet.sol b/contracts/contracts/gateway/GatewayGetterFacet.sol index 7dd47386e..629ea1904 100644 --- a/contracts/contracts/gateway/GatewayGetterFacet.sol +++ b/contracts/contracts/gateway/GatewayGetterFacet.sol @@ -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; diff --git a/contracts/contracts/gateway/GatewayManagerFacet.sol b/contracts/contracts/gateway/GatewayManagerFacet.sol index 52b743593..a75480825 100644 --- a/contracts/contracts/gateway/GatewayManagerFacet.sol +++ b/contracts/contracts/gateway/GatewayManagerFacet.sol @@ -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(); } @@ -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. @@ -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(); } @@ -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. diff --git a/contracts/contracts/gateway/GatewayMessengerFacet.sol b/contracts/contracts/gateway/GatewayMessengerFacet.sol index 472f9763e..727e04d09 100644 --- a/contracts/contracts/gateway/GatewayMessengerFacet.sol +++ b/contracts/contracts/gateway/GatewayMessengerFacet.sol @@ -4,14 +4,17 @@ 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"; @@ -19,19 +22,23 @@ string constant ERR_MULTILEVEL_CROSS_MSG_DISABLED = "Support for multi-level cro 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); @@ -42,14 +49,6 @@ 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)); @@ -57,13 +56,26 @@ contract GatewayMessengerFacet is GatewayActorModifiers { 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}); @@ -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(); } } diff --git a/contracts/contracts/gateway/router/CheckpointingFacet.sol b/contracts/contracts/gateway/router/CheckpointingFacet.sol index 54e2b1e52..31ece0607 100644 --- a/contracts/contracts/gateway/router/CheckpointingFacet.sol +++ b/contracts/contracts/gateway/router/CheckpointingFacet.sol @@ -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"; @@ -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. @@ -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 @@ -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; } diff --git a/contracts/contracts/gateway/router/XnetMessagingFacet.sol b/contracts/contracts/gateway/router/XnetMessagingFacet.sol index c7e3c2a7e..9251b76aa 100644 --- a/contracts/contracts/gateway/router/XnetMessagingFacet.sol +++ b/contracts/contracts/gateway/router/XnetMessagingFacet.sol @@ -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(); } } diff --git a/contracts/contracts/interfaces/IGateway.sol b/contracts/contracts/interfaces/IGateway.sol index 1c807ea81..f50339a9e 100644 --- a/contracts/contracts/interfaces/IGateway.sol +++ b/contracts/contracts/interfaces/IGateway.sol @@ -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; diff --git a/contracts/contracts/interfaces/ISubnetActor.sol b/contracts/contracts/interfaces/ISubnetActor.sol new file mode 100644 index 000000000..5582b4b8f --- /dev/null +++ b/contracts/contracts/interfaces/ISubnetActor.sol @@ -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); +} diff --git a/contracts/contracts/lib/AssetHelper.sol b/contracts/contracts/lib/AssetHelper.sol index cdfe607dd..b7d80e245 100644 --- a/contracts/contracts/lib/AssetHelper.sol +++ b/contracts/contracts/lib/AssetHelper.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; -import {NotEnoughBalance} from "../errors/IPCErrors.sol"; +import {NotEnoughBalance, InvalidSubnetActor} from "../errors/IPCErrors.sol"; import {Asset, AssetKind} from "../structs/Subnet.sol"; import {EMPTY_BYTES} from "../constants/Constants.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {SubnetActorGetterFacet} from "../subnet/SubnetActorGetterFacet.sol"; +import {ISubnetActor} from "../interfaces/ISubnetActor.sol"; /// @notice Helpers to deal with a supply source. library AssetHelper { @@ -16,7 +16,7 @@ library AssetHelper { /// and checks if its supply kind matches the provided one. /// It reverts if the address does not correspond to a subnet actor. function hasSupplyOfKind(address subnetActor, AssetKind compare) internal view returns (bool) { - return SubnetActorGetterFacet(subnetActor).supplySource().kind == compare; + return ISubnetActor(subnetActor).supplySource().kind == compare; } /// @notice Checks that a given supply strategy is correctly formed and its preconditions are met. @@ -37,6 +37,10 @@ library AssetHelper { require(asset.kind == kind, "Unexpected asset"); } + function equals(Asset memory asset, Asset memory asset2) internal pure returns (bool) { + return asset.tokenAddress == asset2.tokenAddress && asset.kind == asset2.kind; + } + /// @notice Locks the specified amount from msg.sender into custody. /// Reverts with NoBalanceIncrease if the token balance does not increase. /// May return more than requested for inflationary tokens due to balance rise. @@ -145,6 +149,15 @@ library AssetHelper { return (success, ret); } + /// @notice Checks if the given address is a contract. + function isContract(address account) internal view returns (bool) { + uint256 size; + assembly { + size := extcodesize(account) + } + return size > 0; + } + /// @dev Adaptation from implementation `openzeppelin-contracts/utils/Address.sol` /// that doesn't revert immediately in case of failure and merely notifies of the outcome. function functionCallWithValue( @@ -156,6 +169,10 @@ library AssetHelper { revert NotEnoughBalance(); } + if (!isContract(target)) { + revert InvalidSubnetActor(); + } + return target.call{value: value}(data); } @@ -196,6 +213,15 @@ library AssetHelper { } } + // @notice Gets the balance of the account. + function balanceOf(Asset memory asset, address holder) internal view returns (uint256 ret) { + if (asset.kind == AssetKind.Native) { + ret = holder.balance; + } else if (asset.kind == AssetKind.ERC20) { + ret = IERC20(asset.tokenAddress).balanceOf(holder); + } + } + // @notice Makes the asset available for spending by the given spender, without actually sending it. // @return msgValue The amount of msg.value that needs to be sent along with the subsequent call that will _actually_ spend that asset. // Will be 0 if the asset is a token, since no native coins are to be sent. @@ -214,4 +240,7 @@ library AssetHelper { return Asset({kind: AssetKind.Native, tokenAddress: address(0)}); } + function erc20(address token) internal pure returns (Asset memory) { + return Asset({kind: AssetKind.ERC20, tokenAddress: token}); + } } \ No newline at end of file diff --git a/contracts/contracts/lib/CrossMsgHelper.sol b/contracts/contracts/lib/CrossMsgHelper.sol index 7abe365d2..7fa53faea 100644 --- a/contracts/contracts/lib/CrossMsgHelper.sol +++ b/contracts/contracts/lib/CrossMsgHelper.sol @@ -7,12 +7,15 @@ import {IPCMsgType} from "../enums/IPCMsgType.sol"; import {SubnetID, IPCAddress} from "../structs/Subnet.sol"; import {SubnetIDHelper} from "../lib/SubnetIDHelper.sol"; import {FvmAddressHelper} from "../lib/FvmAddressHelper.sol"; +import {LibGateway} from "../lib/LibGateway.sol"; import {FvmAddress} from "../structs/FvmAddress.sol"; import {FilAddress} from "fevmate/contracts/utils/FilAddress.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {Asset} from "../structs/Subnet.sol"; import {AssetHelper} from "./AssetHelper.sol"; import {IIpcHandler} from "../../sdk/interfaces/IIpcHandler.sol"; +// solhint-disable-next-line no-global-import +import "../errors/IPCErrors.sol"; /// @title Helper library for manipulating IpcEnvelope-related structs library CrossMsgHelper { @@ -35,7 +38,8 @@ library CrossMsgHelper { to: to, value: value, message: EMPTY_BYTES, - nonce: 0 + originalNonce: 0, + localNonce: 0 }); } @@ -54,7 +58,8 @@ library CrossMsgHelper { to: to, value: value, message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); } @@ -66,11 +71,12 @@ library CrossMsgHelper { OutcomeType outcome, bytes memory ret ) public pure returns (IpcEnvelope memory) { - ResultMsg memory message = ResultMsg({id: toHash(crossMsg), outcome: outcome, ret: ret}); + ResultMsg memory message = ResultMsg({id:toTracingId(crossMsg), outcome: outcome, ret: ret}); + uint256 value = crossMsg.value; + // if the message was executed successfully, the value stayed + // in the subnet and there's no need to return it. if (outcome == OutcomeType.Ok) { - // if the message was executed successfully, the value stayed - // in the subnet and there's no need to return it. value = 0; } return @@ -80,10 +86,12 @@ library CrossMsgHelper { to: crossMsg.from, value: value, message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); } + // creates transfer message from the child subnet to the parent subnet function createReleaseMsg( SubnetID calldata subnet, address signer, @@ -98,6 +106,7 @@ library CrossMsgHelper { ); } + // creates transfer message from the parent subnet to the child subnet function createFundMsg( SubnetID calldata subnet, address signer, @@ -135,6 +144,22 @@ library CrossMsgHelper { return keccak256(abi.encode(crossMsgs)); } + /// @notice Returns a deterministic hash for the given cross message, excluding the nonce, + /// which is useful for generating a `tracingId` for cross messages. + function toTracingId(IpcEnvelope memory crossMsg) internal pure returns (bytes32) { + return keccak256( + // solhint-disable-next-line func-named-parameters + abi.encode( + crossMsg.kind, + crossMsg.to, + crossMsg.from, + crossMsg.value, + crossMsg.message, + crossMsg.originalNonce + ) + ); + } + function isEmpty(IpcEnvelope memory crossMsg) internal pure returns (bool) { // envelopes need to necessarily include a message inside except // if it is a plain `Transfer`. @@ -164,6 +189,10 @@ library CrossMsgHelper { if (crossMsg.kind == IpcMsgKind.Transfer) { return supplySource.transferFunds({recipient: payable(recipient), value: crossMsg.value}); } else if (crossMsg.kind == IpcMsgKind.Call || crossMsg.kind == IpcMsgKind.Result) { + // For a Result message, the idea is to perform a call as this returns control back to the caller. + // If it's an account, there will be no code to invoke, so this will be have like a bare transfer. + // But if the original caller was a contract, this give it control so it can handle the result + // send the envelope directly to the entrypoint // use supplySource so the tokens in the message are handled successfully // and by the right supply source @@ -182,7 +211,7 @@ library CrossMsgHelper { uint256 prevNonce; uint256 length = crossMsgs.length; for (uint256 i; i < length; ) { - uint256 nonce = crossMsgs[i].nonce; + uint256 nonce = crossMsgs[i].localNonce; if (prevNonce >= nonce) { // gas-opt: original check: i > 0 @@ -199,4 +228,8 @@ library CrossMsgHelper { return true; } + + function validateCrossMessage(IpcEnvelope memory crossMsg) internal view returns (bool, InvalidXnetMessageReason, IPCMsgType) { + return LibGateway.checkCrossMessage(crossMsg); + } } diff --git a/contracts/contracts/lib/LibGateway.sol b/contracts/contracts/lib/LibGateway.sol index e48c0dcee..b1cfc67ce 100644 --- a/contracts/contracts/lib/LibGateway.sol +++ b/contracts/contracts/lib/LibGateway.sol @@ -8,11 +8,14 @@ import {SubnetID, Subnet, AssetKind, Asset} from "../structs/Subnet.sol"; import {SubnetActorGetterFacet} from "../subnet/SubnetActorGetterFacet.sol"; import {CallMsg, IpcMsgKind, IpcEnvelope, OutcomeType, BottomUpMsgBatch, BottomUpMsgBatch, BottomUpCheckpoint, ParentFinality} from "../structs/CrossNet.sol"; import {Membership} from "../structs/Subnet.sol"; -import {CannotSendCrossMsgToItself, MethodNotAllowed, MaxMsgsPerBatchExceeded, InvalidXnetMessage ,OldConfigurationNumber, NotRegisteredSubnet, InvalidActorAddress, ParentFinalityAlreadyCommitted, InvalidXnetMessageReason} from "../errors/IPCErrors.sol"; import {CrossMsgHelper} from "../lib/CrossMsgHelper.sol"; import {FilAddress} from "fevmate/contracts/utils/FilAddress.sol"; import {SubnetIDHelper} from "../lib/SubnetIDHelper.sol"; import {AssetHelper} from "../lib/AssetHelper.sol"; +import {ISubnetActor} from "../interfaces/ISubnetActor.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +// solhint-disable-next-line no-global-import +import "../errors/IPCErrors.sol"; library LibGateway { using SubnetIDHelper for SubnetID; @@ -21,12 +24,20 @@ library LibGateway { using SubnetIDHelper for SubnetID; using FilAddress for address payable; using AssetHelper for Asset; + using EnumerableSet for EnumerableSet.Bytes32Set; event MembershipUpdated(Membership); /// @dev subnet refers to the next "down" subnet that the `envelope.message.to` should be forwarded to. - event NewTopDownMessage(address indexed subnet, IpcEnvelope message); + event NewTopDownMessage(address indexed subnet, IpcEnvelope message, bytes32 indexed id); + /// @dev event emitted when there is a new bottom-up message added to the batch. + /// @dev there is no need to emit the message itself, as the message is included in batch. + event QueuedBottomUpMessage(bytes32 indexed id); /// @dev event emitted when there is a new bottom-up message batch to be signed. event NewBottomUpMsgBatch(uint256 indexed epoch); + /// @dev event emmitted when a message is stored in the postbox - to be propagated further. + event MessageStoredInPostbox(bytes32 indexed id); + /// @dev event emmitted when a message is propagated further from the postbox. + event MessagePropagatedFromPostbox(bytes32 id); /// @notice returns the current bottom-up checkpoint /// @return exists - whether the checkpoint exists @@ -229,23 +240,18 @@ library LibGateway { /// @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(IpcEnvelope memory crossMessage) internal { - GatewayActorStorage storage s = LibGatewayActorStorage.appStorage(); - SubnetID memory subnetId = crossMessage.to.subnetId.down(s.networkName); - - (bool registered, Subnet storage subnet) = getSubnet(subnetId); - - if (!registered) { - revert NotRegisteredSubnet(); - } - + function commitTopDownMsg(Subnet storage subnet, IpcEnvelope memory crossMessage) internal { uint64 topDownNonce = subnet.topDownNonce; - crossMessage.nonce = topDownNonce; + crossMessage.localNonce = topDownNonce; + // only set the original nonce if the message is from this subnet + if (crossMessage.from.subnetId.equals(subnet.id)) { + crossMessage.originalNonce = topDownNonce; + } subnet.topDownNonce = topDownNonce + 1; subnet.circSupply += crossMessage.value; - emit NewTopDownMessage({subnet: subnetId.getAddress(), message: crossMessage}); + emit NewTopDownMessage({subnet: subnet.id.getAddress(), message: crossMessage, id: crossMessage.toTracingId()}); } /// @notice Commits a new cross-net message to a message batch for execution @@ -255,7 +261,11 @@ library LibGateway { uint256 epoch = getNextEpoch(block.number, s.bottomUpCheckPeriod); // assign nonce to the message. - crossMessage.nonce = s.bottomUpNonce; + crossMessage.localNonce = s.bottomUpNonce; + // only set the original nonce if the message is from this subnet + if (crossMessage.from.subnetId.equals(s.networkName)) { + crossMessage.originalNonce = s.bottomUpNonce; + } s.bottomUpNonce += 1; // populate the batch for that epoch @@ -265,6 +275,7 @@ library LibGateway { batch.blockHeight = epoch; // we need to use push here to initialize the array. batch.msgs.push(crossMessage); + emit QueuedBottomUpMessage({id: crossMessage.toTracingId()}); return; } @@ -301,6 +312,8 @@ library LibGateway { // to trigger the cutting of the batch. batch.msgs.push(crossMessage); } + + emit QueuedBottomUpMessage({id: crossMessage.toTracingId()}); } /// @notice returns the subnet created by a validator @@ -333,6 +346,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 @@ -347,6 +361,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. @@ -356,6 +383,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()) { @@ -368,16 +408,18 @@ library LibGateway { // slither-disable-next-line uninitialized-local Asset memory supplySource; IPCMsgType applyType = crossMsg.applyType(s.networkName); + // it's ok to revert here, as this is a programming error or a malicious message from validator. if (applyType == IPCMsgType.BottomUp) { - // Load the subnet this message is coming from. Ensure that it exists and that the nonce expectation is met. - (bool registered, Subnet storage subnet) = LibGateway.getSubnet(arrivingFrom); - if (!registered) { - // this means the subnet that sent the bottom up message is not registered, - // we cannot send the receipt back as top down because the subnet is not registered - // we ignore this message for as it's not valid, and it may be someone trying to forge it. - return; + if (expectTopDownOnly) { + revert("Expecting top-down messages only"); } - if (subnet.appliedBottomUpNonce != crossMsg.nonce) { + + // 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.localNonce) { sendReceipt(crossMsg, OutcomeType.SystemErr, abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.Nonce)); return; } @@ -388,7 +430,7 @@ library LibGateway { supplySource = SubnetActorGetterFacet(subnet.id.getActor()).supplySource(); } else if (applyType == IPCMsgType.TopDown) { // Note: there is no need to load the subnet, as a top-down application means that _we_ are the subnet. - if (s.appliedTopDownNonce != crossMsg.nonce) { + if (s.appliedTopDownNonce != crossMsg.localNonce) { sendReceipt(crossMsg, OutcomeType.SystemErr, abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.Nonce)); return; } @@ -405,8 +447,21 @@ library LibGateway { // should increase the appliedNonce to allow the execution of the next message // of the batch (this is way we have this after the nonce logic). if (!crossMsg.to.subnetId.equals(s.networkName)) { + (bool valid, InvalidXnetMessageReason reason) = validateCrossMessage(crossMsg); + if (!valid) { + sendReceipt( + crossMsg, + OutcomeType.SystemErr, + abi.encodeWithSelector(InvalidXnetMessage.selector, reason) + ); + return; + } + bytes32 cid = crossMsg.toHash(); + s.postboxKeys.add(cid); s.postbox[cid] = crossMsg; + + emit MessageStoredInPostbox({id: crossMsg.toTracingId()}); return; } @@ -456,67 +511,29 @@ library LibGateway { // commmit the receipt for propagation // slither-disable-next-line unused-return - commitCrossMessage(original.createResultMsg(outcomeType, ret)); + commitValidatedCrossMessage(original.createResultMsg(outcomeType, ret)); } - + /** * @notice Commit the cross message to storage. * - * @dev It also validates that destination subnet ID is not empty - * and not equal to the current network. - * This function assumes that the funds inside `value` have been - * conveniently minted or burnt already and the message is free to - * use them (see execBottomUpMsgBatch for reference). + * @dev It does not make any validations. They are assumed to be done before calling this function. * @param crossMessage The cross-network message to commit. * @return shouldBurn A Boolean that indicates if the input amount should be burned. */ - function commitCrossMessage(IpcEnvelope memory crossMessage) internal returns (bool shouldBurn) { + function commitValidatedCrossMessage(IpcEnvelope memory crossMessage) internal returns (bool shouldBurn) { GatewayActorStorage storage s = LibGatewayActorStorage.appStorage(); - SubnetID memory to = crossMessage.to.subnetId; - if (to.isEmpty()) { - revert InvalidXnetMessage(InvalidXnetMessageReason.DstSubnet); - } - // destination is the current network, you are better off with a good old message, no cross needed - if (to.equals(s.networkName)) { - revert CannotSendCrossMsgToItself(); - } - SubnetID memory from = crossMessage.from.subnetId; + SubnetID memory to = crossMessage.to.subnetId; IPCMsgType applyType = crossMessage.applyType(s.networkName); - - // Are we the LCA? (Lowest Common Ancestor) - bool isLCA = to.commonParent(from).equals(s.networkName); - - // Even if multi-level messaging is enabled, we reject the xnet message - // as soon as we learn that one of the networks involved use an ERC20 supply source. - // This will block propagation on the first step, or the last step. - // - // TODO IPC does not implement fault handling yet, so if the message fails - // to propagate, the user won't be able to reclaim funds. That's one of the - // reasons xnet messages are disabled by default. - - bool reject = false; - if (applyType == IPCMsgType.BottomUp) { - // We're traversing up, so if we're the first hop, we reject if the subnet was ERC20. - // If we're not the first hop, a child propagated this to us, they made a mistake and - // and we don't have enough info to evaluate. - reject = from.getParentSubnet().equals(s.networkName) && from.getActor().hasSupplyOfKind(AssetKind.ERC20); - } else if (applyType == IPCMsgType.TopDown) { - // We're traversing down. - // Check the next subnet (which can may be the destination subnet). - reject = to.down(s.networkName).getActor().hasSupplyOfKind(AssetKind.ERC20); - } - if (reject) { - if (crossMessage.kind == IpcMsgKind.Transfer) { - revert MethodNotAllowed("propagation of `Transfer` messages not suppported for subnets with ERC20 supply"); - } - } + bool isLCA = to.commonParent(crossMessage.from.subnetId).equals(s.networkName); // If the directionality is top-down, or if we're inverting the direction // because we're the LCA, commit a top-down message. if (applyType == IPCMsgType.TopDown || isLCA) { - ++s.appliedTopDownNonce; - LibGateway.commitTopDownMsg(crossMessage); + (, SubnetID memory subnetId) = to.down(s.networkName); + (, Subnet storage subnet) = getSubnet(subnetId); + LibGateway.commitTopDownMsg(subnet, crossMessage); return (shouldBurn = false); } @@ -526,6 +543,7 @@ library LibGateway { return (shouldBurn = crossMessage.value != 0); } + /** * @dev Performs transaction side-effects from the commitment of a cross-net message. Like * burning funds when bottom-up messages are propagated. @@ -548,4 +566,157 @@ library LibGateway { revert MaxMsgsPerBatchExceeded(); } } + + /// Checks if the incoming and outgoing subnet supply sources can be mapped. + /// Caller should make sure the incoming/outgoing subnets and current subnet are immediate parent/child subnets. + function checkSubnetsSupplyCompatible( + bool isLCA, + IPCMsgType applyType, + SubnetID memory incoming, + SubnetID memory outgoing, + SubnetID memory current + ) internal view returns(bool) { + if (isLCA) { + // now, it's pivoting @ LCA (i.e. upwards => downwards) + // if incoming bottom up subnet and outgoing target subnet have the same + // asset, we will allow it. This is because if they are using the + // same asset, then the asset can be mapped in both subnets. + + (, SubnetID memory incDown) = incoming.down(current); + (, SubnetID memory outDown) = outgoing.down(current); + + Asset memory incAsset = ISubnetActor(incDown.getActor()).supplySource(); + Asset memory outAsset = ISubnetActor(outDown.getActor()).supplySource(); + + return incAsset.equals(outAsset); + } + + if (applyType == IPCMsgType.BottomUp) { + // The child subnet has supply source native, this is the same as + // the current subnet's native source, the mapping makes sense, propagate up. + (, SubnetID memory incDown) = incoming.down(current); + return incDown.getActor().hasSupplyOfKind(AssetKind.Native); + } + + // Topdown handling + + // The incoming subnet's supply source will be mapped to native coin in the + // next child subnet. If the down subnet has native, then the mapping makes + // sense. + (, SubnetID memory down) = outgoing.down(current); + return down.getActor().hasSupplyOfKind(AssetKind.Native); + } + + /// @notice Validates a cross message before committing it. + function validateCrossMessage(IpcEnvelope memory envelope) internal view returns (bool, InvalidXnetMessageReason) { + (bool valid, InvalidXnetMessageReason reason, ) = checkCrossMessage(envelope); + return (valid, reason); + } + + /// @notice Validates a cross message and returns the applyType if the message is valid + function checkCrossMessage(IpcEnvelope memory envelope) internal view returns (bool valid, InvalidXnetMessageReason reason, IPCMsgType applyType) { + SubnetID memory toSubnetId = envelope.to.subnetId; + if (toSubnetId.isEmpty()) { + return (false, InvalidXnetMessageReason.DstSubnet, applyType); + } + + GatewayActorStorage storage s = LibGatewayActorStorage.appStorage(); + SubnetID memory currentNetwork = s.networkName; + + // We cannot send a cross message to the same subnet. + if (toSubnetId.equals(currentNetwork)) { + return (false, InvalidXnetMessageReason.ReflexiveSend, applyType); + } + + // Lowest common ancestor subnet + bool isLCA = toSubnetId.commonParent(envelope.from.subnetId).equals(currentNetwork); + applyType = envelope.applyType(currentNetwork); + + // If the directionality is top-down, or if we're inverting the direction + // else we need to check if the common parent exists. + if (applyType == IPCMsgType.TopDown || isLCA) { + (bool foundChildSubnetId, SubnetID memory childSubnetId) = toSubnetId.down(currentNetwork); + if (!foundChildSubnetId) { + return (false, InvalidXnetMessageReason.DstSubnet, applyType); + } + + (bool foundSubnet,) = LibGateway.getSubnet(childSubnetId); + if (!foundSubnet) { + return (false, InvalidXnetMessageReason.DstSubnet, applyType); + } + } else { + SubnetID memory commonParent = toSubnetId.commonParent(currentNetwork); + if (commonParent.isEmpty()) { + return (false, InvalidXnetMessageReason.NoRoute, applyType); + } + } + + // starting/ending subnet, no need check supply sources + if (envelope.from.subnetId.equals(currentNetwork) || envelope.to.subnetId.equals(currentNetwork)) { + return (true, reason, applyType); + } + + bool supplySourcesCompatible = checkSubnetsSupplyCompatible({ + isLCA: isLCA, + applyType: applyType, + incoming: envelope.from.subnetId, + outgoing: envelope.to.subnetId, + current: currentNetwork + }); + + if (!supplySourcesCompatible) { + return (false, InvalidXnetMessageReason.IncompatibleSupplySource, applyType); + } + + return (true, reason, applyType); + } + + /** + * @dev Propagates all the populated cross-net messages from the postbox. + */ + function propagateAllPostboxMessages() internal { + GatewayActorStorage storage s = LibGatewayActorStorage.appStorage(); + + uint256 keysLength = s.postboxKeys.length(); + + bytes32[] memory values = s.postboxKeys.values(); + + for (uint256 i = 0; i < keysLength; ) { + bytes32 msgCid = values[i]; + LibGateway.propagatePostboxMessage(msgCid); + + unchecked { + ++i; + } + } + } + + /** + * @dev Propagates the populated cross-net message for the given `msgCid`. + * @param msgCid - the cid of the cross-net message + */ + function propagatePostboxMessage(bytes32 msgCid) internal { + GatewayActorStorage storage s = LibGatewayActorStorage.appStorage(); + IpcEnvelope storage crossMsg = s.postbox[msgCid]; + + if (crossMsg.isEmpty()) { + revert("Message not found in postbox"); + } + + bool shouldBurn = LibGateway.commitValidatedCrossMessage(crossMsg); + + // Cache value before deletion to avoid re-entrancy + uint256 v = crossMsg.value; + bytes32 deterministicId = crossMsg.toTracingId(); + + // Remove the message to prevent re-entrancy and clean up state + delete s.postbox[msgCid]; + s.postboxKeys.remove(msgCid); + + // Execute side effects + LibGateway.crossMsgSideEffects({v: v, shouldBurn: shouldBurn}); + + emit MessagePropagatedFromPostbox({id: deterministicId}); + } + } diff --git a/contracts/contracts/lib/LibGatewayActorStorage.sol b/contracts/contracts/lib/LibGatewayActorStorage.sol index 4cb63536e..fbf2c8301 100644 --- a/contracts/contracts/lib/LibGatewayActorStorage.sol +++ b/contracts/contracts/lib/LibGatewayActorStorage.sol @@ -65,6 +65,8 @@ struct GatewayActorStorage { /// an actor that need to be propagated further through the hierarchy. /// cross-net message id => CrossMsg mapping(bytes32 => IpcEnvelope) postbox; + /// @notice Keys of the envelopes in the postbox. Useful to iterate through them + EnumerableSet.Bytes32Set postboxKeys; /// @notice A mapping of block numbers to bottom-up checkpoints // slither-disable-next-line uninitialized-state mapping(uint256 => BottomUpCheckpoint) bottomUpCheckpoints; diff --git a/contracts/contracts/lib/SubnetIDHelper.sol b/contracts/contracts/lib/SubnetIDHelper.sol index 127d53f1f..bf0e1dde3 100644 --- a/contracts/contracts/lib/SubnetIDHelper.sol +++ b/contracts/contracts/lib/SubnetIDHelper.sol @@ -12,8 +12,6 @@ library SubnetIDHelper { error NoParentForSubnet(); error NoAddressForRoot(); error EmptySubnet(); - error DifferentRootNetwork(); - error InvalidRoute(); function getAddress(SubnetID memory subnet) public pure returns (address) { uint256 length = subnet.route.length; @@ -130,13 +128,13 @@ library SubnetIDHelper { /// down in the path from the subnet id given as argument. /// subnet2 needs to be a prefix of the subnet1. /// If subnet1 is /a/b/c/d and subnet2 is /a/b, then the returned ID should be /a/b/c. - /// @dev Revert will be triggered if subnet2 is an invalid input. - function down(SubnetID calldata subnet1, SubnetID calldata subnet2) public pure returns (SubnetID memory) { + /// @dev Returns an empty SubnetID if subnet2 is not a prefix of subnet1 or if the roots are different. + function down(SubnetID calldata subnet1, SubnetID calldata subnet2) public pure returns (bool, SubnetID memory) { if (subnet1.root != subnet2.root) { - revert DifferentRootNetwork(); + return (false, SubnetID({root: 0, route: new address[](0)})); } if (subnet1.route.length <= subnet2.route.length) { - revert InvalidRoute(); + return (false, SubnetID({root: 0, route: new address[](0)})); } uint256 i; @@ -158,7 +156,7 @@ library SubnetIDHelper { } } - return SubnetID({root: subnet1.root, route: route}); + return (true, SubnetID({root: subnet1.root, route: route})); } function isEmpty(SubnetID calldata subnetId) public pure returns (bool) { diff --git a/contracts/contracts/structs/CrossNet.sol b/contracts/contracts/structs/CrossNet.sol index 1f5962346..857c75527 100644 --- a/contracts/contracts/structs/CrossNet.sol +++ b/contracts/contracts/structs/CrossNet.sol @@ -74,15 +74,26 @@ struct IpcEnvelope { /// @dev address sending the message IPCAddress from; /// @dev outgoing nonce for the envelope. - /// This nonce is set by the gateway when committing the message for propagation - uint64 nonce; - /// @dev value being sent in the message. - /// If we want receipts to return value, and all messages to be able - /// to handle different supply sources we can expose the value - /// as a common field. + /// This nonce is set by the gateway when committing the message for propagation. + /// This nonce is changed on each network when the message is propagated, + /// so it is unique for each network and prevents replay attacks. + uint64 localNonce; + /// @dev Value being sent in the message. + /// For `Call` and `Result` kinds, the `value` field is synthetic and does not represent an actual token or native currency transfer. + /// Instead, it serves as metadata or an abstract representation of value to be interpreted by the target contract or receipt handler. + /// + /// For example, in a `Call` message, `value` might represent the intended payment amount for a service in a cross-network dApp, + /// allowing the receiving contract to process it as part of its logic, regardless of the actual token transfer mechanics. + /// Similarly, in a `Result` message, `value` might represent the outcome of a transaction, such as the total tokens minted or refunded. + /// + /// For `Transfer` messages, `value` represents the actual amount of native tokens being transferred across networks. uint256 value; /// @dev abi.encoded message bytes message; + /// @dev original nonce of the message from the source network. + /// It is set once at the source network and remains unchanged during propagation. + /// It is used to generate a unique tracing ID across networks, which is useful for debugging and auditing purposes. + uint64 originalNonce; /// @dev the gas limit is currently not used. // FIXME: currently not used. // uint256 gasLimit; diff --git a/contracts/contracts/subnet/SubnetActorCheckpointingFacet.sol b/contracts/contracts/subnet/SubnetActorCheckpointingFacet.sol index 160ab9e1d..14f294277 100644 --- a/contracts/contracts/subnet/SubnetActorCheckpointingFacet.sol +++ b/contracts/contracts/subnet/SubnetActorCheckpointingFacet.sol @@ -47,9 +47,11 @@ contract SubnetActorCheckpointingFacet is SubnetActorModifiers, ReentrancyGuard, IGateway(s.ipcGatewayAddr).commitCheckpoint(checkpoint); LibActivity.recordActivityRollup(checkpoint.subnetID, uint64(checkpoint.blockHeight), checkpoint.activity); - // confirming the changes in membership in the child LibStaking.confirmChange(checkpoint.nextConfigurationNumber); + + // Propagate cross messages from checkpoint to other subnets + IGateway(s.ipcGatewayAddr).propagateAll(); } /// @notice Checks whether the signatures are valid for the provided signatories and hash within the current validator set. diff --git a/contracts/sdk/IpcContract.sol b/contracts/sdk/IpcContract.sol index d329684dc..ff18092d2 100644 --- a/contracts/sdk/IpcContract.sol +++ b/contracts/sdk/IpcContract.sol @@ -79,7 +79,8 @@ abstract contract IpcExchange is IIpcHandler, Ownable, ReentrancyGuard { kind: IpcMsgKind.Call, from: to, // TODO: will anyway be replaced by sendContractXnetMessage. to: to, - nonce: 0, // TODO: will be replaced. + localNonce: 0, // TODO: will be replaced. + originalNonce: 0, // TODO: will be replaced value: value, message: abi.encode(callMsg) }) diff --git a/contracts/sdk/IpcContractUpgradeable.sol b/contracts/sdk/IpcContractUpgradeable.sol index 1c4be0e2a..4d906d735 100644 --- a/contracts/sdk/IpcContractUpgradeable.sol +++ b/contracts/sdk/IpcContractUpgradeable.sol @@ -90,7 +90,8 @@ abstract contract IpcExchangeUpgradeable is Initializable, IIpcHandler, OwnableU kind: IpcMsgKind.Call, from: to, // TODO: will anyway be replaced by sendContractXnetMessage. to: to, - nonce: 0, // TODO: will be replaced. + localNonce: 0, // TODO: will be replaced. + originalNonce: 0, // TODO: will be replaced. value: value, message: abi.encode(callMsg) }) diff --git a/contracts/tasks/cross-network-messenger.ts b/contracts/tasks/cross-network-messenger.ts new file mode 100644 index 000000000..0dd221466 --- /dev/null +++ b/contracts/tasks/cross-network-messenger.ts @@ -0,0 +1,46 @@ +import { task } from 'hardhat/config' +import { HardhatRuntimeEnvironment, TaskArguments } from 'hardhat/types' +import { Deployments } from './lib' + +// step 1. deploy the cross network messenger util contract +// sample command: pnpm exec hardhat cross-network-messenger-deploy --network calibrationnet +task('cross-network-messenger-deploy') + .addPositionalParam('gatewayAddr', 'the address of the gateway contract') + .setDescription('Deploy example cross network messenger util contract') + .setAction(async (args: TaskArguments, hre: HardhatRuntimeEnvironment) => { + await hre.run('compile') + + const [deployer] = await hre.getUnnamedAccounts() + const balance = await hre.ethers.provider.getBalance(deployer) + console.log( + `Deploying cross network messenger contract with account: ${deployer} and balance: ${hre.ethers.utils.formatEther(balance.toString())}`, + ) + + await Deployments.deploy(hre, deployer, { + name: 'CrossMessengerCaller', + args: [args.gatewayAddr], + libraries: ['SubnetIDHelper'], + }) + }) + +// step 2. invoke a cross network send message +// sample command: pnpm exec hardhat cross-network-send --network calibrationnet 314159 +task('cross-network-send') + .addPositionalParam('root', 'the chain id of root subnet') + .addPositionalParam('route', 'the addresses of the subnet routes, use "," to separate the addresses') + .addPositionalParam('recipient', 'the recipient of the send') + .addPositionalParam('value', 'the value to send over') + .setDescription('Invoke a cross network send in the target subnet') + .setAction(async (args: TaskArguments, hre: HardhatRuntimeEnvironment) => { + await hre.run('compile') + + const subnetId = { root: args.root, route: args.route.split(',') } + console.log('sending to subnet', subnetId) + + const amount = hre.ethers.utils.parseEther(args.value) + console.log('sending to address', args.recipient, 'with amount', amount) + + const contracts = await Deployments.resolve(hre, 'CrossMessengerCaller') + const contract = contracts.contracts.CrossMessengerCaller + await contract.invokeSendMessage(subnetId, args.recipient, amount, { value: Number(amount) }) + }) diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts index d0ab1c692..968f53e9a 100644 --- a/contracts/tasks/index.ts +++ b/contracts/tasks/index.ts @@ -7,3 +7,4 @@ import './upgrade' import './validator-gater' import './validator-rewarder' import './gen-selector-library' +import './cross-network-messenger' diff --git a/contracts/test/IntegrationTestBase.sol b/contracts/test/IntegrationTestBase.sol index 19013b3d7..b2904d811 100644 --- a/contracts/test/IntegrationTestBase.sol +++ b/contracts/test/IntegrationTestBase.sol @@ -802,7 +802,8 @@ contract IntegrationTestBase is Test, TestParams, TestRegistry, TestSubnetActor, rawAddress: FvmAddressHelper.from(src) }), value: DEFAULT_CROSS_MSG_FEE + 1, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: EMPTY_BYTES }); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); diff --git a/contracts/test/helpers/SelectorLibrary.sol b/contracts/test/helpers/SelectorLibrary.sol index 88ff96643..740e9e41f 100644 --- a/contracts/test/helpers/SelectorLibrary.sol +++ b/contracts/test/helpers/SelectorLibrary.sol @@ -27,7 +27,7 @@ library SelectorLibrary { if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("GatewayGetterFacet"))) { return abi.decode( - hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000218789f83b0000000000000000000000000000000000000000000000000000000006c46853000000000000000000000000000000000000000000000000000000002da5794a00000000000000000000000000000000000000000000000000000000dd81b5cf0000000000000000000000000000000000000000000000000000000041b6a2e80000000000000000000000000000000000000000000000000000000038d6693200000000000000000000000000000000000000000000000000000000b3ab3f7400000000000000000000000000000000000000000000000000000000ac12d763000000000000000000000000000000000000000000000000000000004aa8f8a500000000000000000000000000000000000000000000000000000000ca41d5ce00000000000000000000000000000000000000000000000000000000444ead5100000000000000000000000000000000000000000000000000000000d6c5c39700000000000000000000000000000000000000000000000000000000544dddff000000000000000000000000000000000000000000000000000000006ad21bb000000000000000000000000000000000000000000000000000000000a517218f000000000000000000000000000000000000000000000000000000009704276600000000000000000000000000000000000000000000000000000000b1ba49b000000000000000000000000000000000000000000000000000000000f3229131000000000000000000000000000000000000000000000000000000000338150f0000000000000000000000000000000000000000000000000000000094074b03000000000000000000000000000000000000000000000000000000007edeac920000000000000000000000000000000000000000000000000000000006572c1a00000000000000000000000000000000000000000000000000000000c66c66a1000000000000000000000000000000000000000000000000000000003594c3c1000000000000000000000000000000000000000000000000000000009d3070b50000000000000000000000000000000000000000000000000000000042398a9a00000000000000000000000000000000000000000000000000000000fa34a400000000000000000000000000000000000000000000000000000000005d02968500000000000000000000000000000000000000000000000000000000599c7bd10000000000000000000000000000000000000000000000000000000005aff0b3000000000000000000000000000000000000000000000000000000008cfd78e70000000000000000000000000000000000000000000000000000000002e30f9a00000000000000000000000000000000000000000000000000000000a2b6715800000000000000000000000000000000000000000000000000000000", + hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000228789f83b0000000000000000000000000000000000000000000000000000000006c46853000000000000000000000000000000000000000000000000000000002da5794a00000000000000000000000000000000000000000000000000000000dd81b5cf0000000000000000000000000000000000000000000000000000000041b6a2e80000000000000000000000000000000000000000000000000000000038d6693200000000000000000000000000000000000000000000000000000000b3ab3f7400000000000000000000000000000000000000000000000000000000ac12d763000000000000000000000000000000000000000000000000000000004aa8f8a500000000000000000000000000000000000000000000000000000000ca41d5ce00000000000000000000000000000000000000000000000000000000444ead5100000000000000000000000000000000000000000000000000000000d6c5c39700000000000000000000000000000000000000000000000000000000544dddff000000000000000000000000000000000000000000000000000000006ad21bb000000000000000000000000000000000000000000000000000000000a517218f000000000000000000000000000000000000000000000000000000009704276600000000000000000000000000000000000000000000000000000000b1ba49b000000000000000000000000000000000000000000000000000000000f3229131000000000000000000000000000000000000000000000000000000000338150f0000000000000000000000000000000000000000000000000000000094074b03000000000000000000000000000000000000000000000000000000007edeac920000000000000000000000000000000000000000000000000000000006572c1a00000000000000000000000000000000000000000000000000000000c66c66a1000000000000000000000000000000000000000000000000000000003594c3c1000000000000000000000000000000000000000000000000000000009d3070b50000000000000000000000000000000000000000000000000000000042398a9a00000000000000000000000000000000000000000000000000000000fa34a400000000000000000000000000000000000000000000000000000000005d02968500000000000000000000000000000000000000000000000000000000599c7bd10000000000000000000000000000000000000000000000000000000005aff0b3000000000000000000000000000000000000000000000000000000008cfd78e7000000000000000000000000000000000000000000000000000000007474d79f0000000000000000000000000000000000000000000000000000000002e30f9a00000000000000000000000000000000000000000000000000000000a2b6715800000000000000000000000000000000000000000000000000000000", (bytes4[]) ); } @@ -41,14 +41,14 @@ library SelectorLibrary { if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("GatewayMessengerFacet"))) { return abi.decode( - hex"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000225bf0db6000000000000000000000000000000000000000000000000000000003eeb723f00000000000000000000000000000000000000000000000000000000", + hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000027f7999f400000000000000000000000000000000000000000000000000000000dcf7a9a000000000000000000000000000000000000000000000000000000000", (bytes4[]) ); } if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("CheckpointingFacet"))) { return abi.decode( - hex"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000453b4e7bf00000000000000000000000000000000000000000000000000000000a031667200000000000000000000000000000000000000000000000000000000d8b4602500000000000000000000000000000000000000000000000000000000ac81837900000000000000000000000000000000000000000000000000000000", + hex"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000453b4e7bf000000000000000000000000000000000000000000000000000000000add1e1f00000000000000000000000000000000000000000000000000000000d57d455700000000000000000000000000000000000000000000000000000000ac81837900000000000000000000000000000000000000000000000000000000", (bytes4[]) ); } @@ -62,14 +62,14 @@ library SelectorLibrary { if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("XnetMessagingFacet"))) { return abi.decode( - hex"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001dd8319ee00000000000000000000000000000000000000000000000000000000", + hex"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001b005393700000000000000000000000000000000000000000000000000000000", (bytes4[]) ); } if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("SubnetActorGetterFacet"))) { return abi.decode( - hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000223354c3e10000000000000000000000000000000000000000000000000000000035142c8c0000000000000000000000000000000000000000000000000000000006c46853000000000000000000000000000000000000000000000000000000004b27aa72000000000000000000000000000000000000000000000000000000004b0694e200000000000000000000000000000000000000000000000000000000b6797d3c000000000000000000000000000000000000000000000000000000008ef3f76100000000000000000000000000000000000000000000000000000000e02d971b00000000000000000000000000000000000000000000000000000000903e693000000000000000000000000000000000000000000000000000000000948628a900000000000000000000000000000000000000000000000000000000d92e8f12000000000000000000000000000000000000000000000000000000009de7025800000000000000000000000000000000000000000000000000000000c7cda762000000000000000000000000000000000000000000000000000000009754b29e0000000000000000000000000000000000000000000000000000000038a210b30000000000000000000000000000000000000000000000000000000080f76021000000000000000000000000000000000000000000000000000000005dd9147c00000000000000000000000000000000000000000000000000000000d6eb591000000000000000000000000000000000000000000000000000000000332a5ac9000000000000000000000000000000000000000000000000000000001597bf7e0000000000000000000000000000000000000000000000000000000052d182d1000000000000000000000000000000000000000000000000000000001904bb2e000000000000000000000000000000000000000000000000000000006ad04c7900000000000000000000000000000000000000000000000000000000cfca28240000000000000000000000000000000000000000000000000000000040550a1c00000000000000000000000000000000000000000000000000000000d081be03000000000000000000000000000000000000000000000000000000001f3a0e410000000000000000000000000000000000000000000000000000000072d0a0e000000000000000000000000000000000000000000000000000000000599c7bd1000000000000000000000000000000000000000000000000000000009e33bd0200000000000000000000000000000000000000000000000000000000c5ab224100000000000000000000000000000000000000000000000000000000f0cf6c9600000000000000000000000000000000000000000000000000000000ad81e4d60000000000000000000000000000000000000000000000000000000080875df700000000000000000000000000000000000000000000000000000000", + hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000223354c3e10000000000000000000000000000000000000000000000000000000035142c8c0000000000000000000000000000000000000000000000000000000006c46853000000000000000000000000000000000000000000000000000000004b27aa72000000000000000000000000000000000000000000000000000000004b0694e200000000000000000000000000000000000000000000000000000000b6797d3c000000000000000000000000000000000000000000000000000000008ef3f76100000000000000000000000000000000000000000000000000000000797196de00000000000000000000000000000000000000000000000000000000903e693000000000000000000000000000000000000000000000000000000000948628a900000000000000000000000000000000000000000000000000000000d92e8f12000000000000000000000000000000000000000000000000000000009de7025800000000000000000000000000000000000000000000000000000000c7cda762000000000000000000000000000000000000000000000000000000009754b29e0000000000000000000000000000000000000000000000000000000038a210b30000000000000000000000000000000000000000000000000000000080f76021000000000000000000000000000000000000000000000000000000005dd9147c00000000000000000000000000000000000000000000000000000000d6eb591000000000000000000000000000000000000000000000000000000000332a5ac9000000000000000000000000000000000000000000000000000000001597bf7e0000000000000000000000000000000000000000000000000000000052d182d1000000000000000000000000000000000000000000000000000000001904bb2e000000000000000000000000000000000000000000000000000000006ad04c7900000000000000000000000000000000000000000000000000000000cfca28240000000000000000000000000000000000000000000000000000000040550a1c00000000000000000000000000000000000000000000000000000000d081be03000000000000000000000000000000000000000000000000000000001f3a0e410000000000000000000000000000000000000000000000000000000072d0a0e000000000000000000000000000000000000000000000000000000000599c7bd1000000000000000000000000000000000000000000000000000000009e33bd0200000000000000000000000000000000000000000000000000000000c5ab224100000000000000000000000000000000000000000000000000000000f0cf6c9600000000000000000000000000000000000000000000000000000000ad81e4d60000000000000000000000000000000000000000000000000000000080875df700000000000000000000000000000000000000000000000000000000", (bytes4[]) ); } @@ -97,7 +97,7 @@ library SelectorLibrary { if (keccak256(abi.encodePacked(facetName)) == keccak256(abi.encodePacked("SubnetActorCheckpointingFacet"))) { return abi.decode( - hex"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002dcab3d7800000000000000000000000000000000000000000000000000000000cc2dc2b900000000000000000000000000000000000000000000000000000000", + hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000026e029c3100000000000000000000000000000000000000000000000000000000cc2dc2b900000000000000000000000000000000000000000000000000000000", (bytes4[]) ); } diff --git a/contracts/test/helpers/TestUtils.sol b/contracts/test/helpers/TestUtils.sol index 5df49f886..32918b7f0 100644 --- a/contracts/test/helpers/TestUtils.sol +++ b/contracts/test/helpers/TestUtils.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.23; import "forge-std/Test.sol"; import "elliptic-curve-solidity/contracts/EllipticCurve.sol"; import {IPCAddress, Asset} from "../../contracts/structs/Subnet.sol"; -import {CallMsg, IpcMsgKind, IpcEnvelope} from "../../contracts/structs/CrossNet.sol"; +import {CallMsg, IpcMsgKind, IpcEnvelope, ResultMsg} from "../../contracts/structs/CrossNet.sol"; import {IIpcHandler} from "../../sdk/interfaces/IIpcHandler.sol"; import {METHOD_SEND, EMPTY_BYTES} from "../../contracts/constants/Constants.sol"; @@ -167,7 +167,8 @@ library TestUtils { to: to, value: value, message: abi.encode(message), - nonce: nonce + originalNonce: 0, + localNonce: nonce }); } } @@ -226,3 +227,30 @@ contract MockIpcContractPayable is IIpcHandler { receive() external payable {} } + +contract MockFallbackContract { + fallback() external payable {} +} + +contract MockIpcContractResult is IIpcHandler { + ResultMsg _result; + bool _hasResult; + + function handleIpcMessage(IpcEnvelope calldata envelope) external payable returns (bytes memory) { + if (envelope.kind == IpcMsgKind.Result) { + _result = abi.decode(envelope.message, (ResultMsg)); + _hasResult = true; + return EMPTY_BYTES; + } + + return EMPTY_BYTES; + } + + function hasResult() public view returns (bool) { + return _hasResult; + } + + function result() public view returns (ResultMsg memory) { + return _result; + } +} diff --git a/contracts/test/integration/GatewayDiamond.t.sol b/contracts/test/integration/GatewayDiamond.t.sol index 6a96a6c3b..12b65b315 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"; @@ -541,28 +541,6 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT gatewayDiamond.manager().kill(); } - function testGatewayDiamond_SendCrossMessage_Fails_NoFunds() public { - address caller = address(new MockIpcContract()); - vm.startPrank(caller); - vm.deal(caller, DEFAULT_COLLATERAL_AMOUNT + DEFAULT_CROSS_MSG_FEE + 2); - registerSubnet(DEFAULT_COLLATERAL_AMOUNT, caller); - - SubnetID memory destinationSubnet = gatewayDiamond.getter().getNetworkName().createSubnetId(caller); - - vm.expectRevert(abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.Value)); - gatewayDiamond.messenger().sendContractXnetMessage{value: DEFAULT_CROSS_MSG_FEE}( - TestUtils.newXnetCallMsg( - IPCAddress({ - subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), - rawAddress: FvmAddressHelper.from(caller) - }), - IPCAddress({subnetId: destinationSubnet, rawAddress: FvmAddressHelper.from(caller)}), - 1, - 0 - ) - ); - } - function testGatewayDiamond_SendCrossMessage_Fails_Fuzz(uint256 fee) public { vm.assume(fee < DEFAULT_CROSS_MSG_FEE); @@ -867,7 +845,7 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT registerSubnet(DEFAULT_COLLATERAL_AMOUNT, caller); SubnetID memory destinationSubnet = gatewayDiamond.getter().getNetworkName(); - vm.expectRevert(CannotSendCrossMsgToItself.selector); + vm.expectRevert(abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.ReflexiveSend)); gatewayDiamond.messenger().sendContractXnetMessage{value: 1}( TestUtils.newXnetCallMsg( IPCAddress({ @@ -881,27 +859,6 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT ); } - function testGatewayDiamond_SendCrossMessage_Fails_Failes_InvalidCrossMsgValue() public { - address caller = address(new MockIpcContract()); - vm.startPrank(caller); - vm.deal(caller, DEFAULT_COLLATERAL_AMOUNT + DEFAULT_CROSS_MSG_FEE + 2); - registerSubnet(DEFAULT_COLLATERAL_AMOUNT, caller); - SubnetID memory destinationSubnet = gatewayDiamond.getter().getNetworkName().createSubnetId(caller); - - vm.expectRevert(abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.Value)); - gatewayDiamond.messenger().sendContractXnetMessage{value: DEFAULT_CROSS_MSG_FEE}( - TestUtils.newXnetCallMsg( - IPCAddress({ - subnetId: SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}), - rawAddress: FvmAddressHelper.from(caller) - }), - IPCAddress({subnetId: destinationSubnet, rawAddress: FvmAddressHelper.from(caller)}), - 5, - 0 - ) - ); - } - // TODO: this is no longer possible because EOA cannot be subnet // function testGatewayDiamond_SendCrossMessage_Fails_EoACaller() public { // address caller = vm.addr(100); @@ -1185,6 +1142,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); @@ -1210,7 +1169,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 @@ -1230,7 +1189,8 @@ contract GatewayActorDiamondTest is Test, IntegrationTestBase, SubnetWithNativeT gatewayDiamond.checkpointer().commitCheckpoint(checkpoint); (, subnetInfo) = gatewayDiamond.getter().getSubnet(subnetId); - require(subnetInfo.circSupply == DEFAULT_COLLATERAL_AMOUNT - 10 * amount, "unexpected circulating supply"); + // cross net messages with Call kind does not affect the circulating supply + require(subnetInfo.circSupply == DEFAULT_COLLATERAL_AMOUNT, "unexpected circulating supply"); } function testGatewayDiamond_listIncompleteCheckpoints() public { diff --git a/contracts/test/integration/GatewayDiamondToken.t.sol b/contracts/test/integration/GatewayDiamondToken.t.sol index b1d01eb35..586efb482 100644 --- a/contracts/test/integration/GatewayDiamondToken.t.sol +++ b/contracts/test/integration/GatewayDiamondToken.t.sol @@ -113,7 +113,7 @@ contract GatewayDiamondTokenTest is Test, IntegrationTestBase { 10 ); vm.expectEmit(true, true, true, true, address(gatewayDiamond)); - emit LibGateway.NewTopDownMessage(address(saDiamond), expected); + emit LibGateway.NewTopDownMessage(address(saDiamond), expected, expected.toTracingId()); gatewayDiamond.manager().fundWithToken(subnet.id, FvmAddressHelper.from(caller), 10); // Assert post-conditions. @@ -191,8 +191,7 @@ contract GatewayDiamondTokenTest is Test, IntegrationTestBase { gatewayDiamond.checkpointer().commitCheckpoint(batch); } - // Call a smart contract in the parent through a smart contract and with - // an ERC20 token supply. + // Call a smart contract in the parent through a smart contract. function test_childToParentCall() public { Subnet memory subnet = createTokenSubnet(address(token)); diff --git a/contracts/test/integration/L2GatewayDiamond.t.sol b/contracts/test/integration/L2GatewayDiamond.t.sol index 69409fae6..83d2637d0 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; @@ -45,11 +47,11 @@ contract L2GatewayActorDiamondTest is Test, L2GatewayActorDiamond { IpcEnvelope[] memory topDownMsgs = new IpcEnvelope[](n); for (uint64 i = 0; i < n; i++) { topDownMsgs[i] = TestUtils.newXnetCallMsg( - IPCAddress({subnetId: id, rawAddress: FvmAddressHelper.from(address(this))}), IPCAddress({ subnetId: gatewayDiamond.getter().getNetworkName().getParentSubnet(), rawAddress: FvmAddressHelper.from(receipient) }), + IPCAddress({subnetId: id, rawAddress: FvmAddressHelper.from(address(this))}), 0, i ); @@ -65,64 +67,9 @@ 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); - - vm.deal(caller, 1 ether); - - vm.expectCall(caller, 1 ether, new bytes(0), 1); - vm.prank(caller); - gatewayDiamond.messenger().propagate{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().propagate{value: 0}(postboxId); - require(caller.balance == 0, "unexpected balance"); - } - - function setupWhiteListMethod(address caller) internal returns (bytes32) { - registerSubnet(DEFAULT_COLLATERAL_AMOUNT, address(this)); - - IpcEnvelope memory crossMsg = TestUtils.newXnetCallMsg( - IPCAddress({ - subnetId: gatewayDiamond.getter().getNetworkName().createSubnetId(caller), - rawAddress: FvmAddressHelper.from(caller) - }), - IPCAddress({ - subnetId: gatewayDiamond.getter().getNetworkName().createSubnetId(address(this)), - rawAddress: FvmAddressHelper.from(address(this)) - }), - DEFAULT_CROSS_MSG_FEE + 1, - 0 - ); - IpcEnvelope[] memory msgs = new IpcEnvelope[](1); - msgs[0] = crossMsg; - - vm.prank(FilAddress.SYSTEM_ACTOR); - gatewayDiamond.xnetMessenger().applyCrossMessages(msgs); + function callback() public view {} - return crossMsg.toHash(); + function collateralSource() external pure returns (Asset memory supply) { + return AssetHelper.native(); } - - function callback() public view {} } diff --git a/contracts/test/integration/L2PlusSubnet.t.sol b/contracts/test/integration/L2PlusSubnet.t.sol new file mode 100644 index 000000000..be41e7cdf --- /dev/null +++ b/contracts/test/integration/L2PlusSubnet.t.sol @@ -0,0 +1,968 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "../../contracts/errors/IPCErrors.sol"; +import {EMPTY_BYTES} from "../../contracts/constants/Constants.sol"; +import {IpcEnvelope, BottomUpMsgBatch, BottomUpCheckpoint, ParentFinality, IpcMsgKind, OutcomeType} from "../../contracts/structs/CrossNet.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} from "../../contracts/GatewayDiamond.sol"; +import {SubnetActorDiamond} from "../../contracts/SubnetActorDiamond.sol"; +import {SubnetActorManagerFacet} from "../../contracts/subnet/SubnetActorManagerFacet.sol"; +import {SubnetActorCheckpointingFacet} from "../../contracts/subnet/SubnetActorCheckpointingFacet.sol"; +import {GatewayGetterFacet} from "../../contracts/gateway/GatewayGetterFacet.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 {IntegrationTestBase, RootSubnetDefinition, TestSubnetDefinition} from "../IntegrationTestBase.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 {ActivityHelper} from "../helpers/ActivityHelper.sol"; + +import "forge-std/console.sol"; + +contract L2PlusSubnetTest is Test, IntegrationTestBase { + using SubnetIDHelper for SubnetID; + using CrossMsgHelper for IpcEnvelope; + using GatewayFacetsHelper for GatewayDiamond; + using SubnetActorFacetsHelper for SubnetActorDiamond; + using AssetHelper for Asset; + + RootSubnetDefinition public rootNetwork; + // native subnets + TestSubnetDefinition public nativeL2Subnet; + TestSubnetDefinition[] public nativeL3Subnets; + + // token subnets + IERC20 public token; + TestSubnetDefinition public tokenL2Subnet; + TestSubnetDefinition[] public nativeL3SubnetsWithTokenParent; + IERC20 public tokenL3; + TestSubnetDefinition[] public tokenL3SubnetsWithTokenParent; + + function setUp() public override { + SubnetID memory rootNetworkName = SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}); + require(rootNetworkName.isRoot(), "not root"); + + GatewayDiamond rootGateway = createGatewayDiamond(gatewayParams(rootNetworkName)); + + rootNetwork = RootSubnetDefinition({ + gateway: rootGateway, + gatewayAddr: address(rootGateway), + id: rootNetworkName + }); + + nativeL2Subnet = createNativeSubnet(rootNetwork.gatewayAddr, rootNetwork.id); + + nativeL3Subnets.push(createNativeSubnet(nativeL2Subnet.gatewayAddr, nativeL2Subnet.id)); + nativeL3Subnets.push(createNativeSubnet(nativeL2Subnet.gatewayAddr, nativeL2Subnet.id)); + + token = new ERC20PresetFixedSupply("TestToken", "TEST", 1_000_000, address(this)); + tokenL2Subnet = createTokenSubnet(address(token), rootNetwork.gatewayAddr, rootNetworkName); + + nativeL3SubnetsWithTokenParent.push(createNativeSubnet(tokenL2Subnet.gatewayAddr, tokenL2Subnet.id)); + nativeL3SubnetsWithTokenParent.push(createNativeSubnet(tokenL2Subnet.gatewayAddr, tokenL2Subnet.id)); + + tokenL3 = new ERC20PresetFixedSupply("TestL3Token", "TEST3", 1_000_000, address(this)); + + tokenL3SubnetsWithTokenParent.push( + createTokenSubnet(address(tokenL3), tokenL2Subnet.gatewayAddr, tokenL2Subnet.id) + ); + tokenL3SubnetsWithTokenParent.push( + createTokenSubnet(address(tokenL3), tokenL2Subnet.gatewayAddr, tokenL2Subnet.id) + ); + + printActors(); + } + + function createNativeSubnet( + address parentGatewayAddress, + SubnetID memory parentNetworkName + ) internal returns (TestSubnetDefinition memory) { + SubnetActorDiamond subnetActor = createSubnetActor( + defaultSubnetActorParamsWith(parentGatewayAddress, parentNetworkName) + ); + + return createSubnet(parentNetworkName.route, subnetActor); + } + + function createTokenSubnet( + address tokenAddress, + address parentGatewayAddress, + SubnetID memory parentNetworkName + ) internal returns (TestSubnetDefinition memory) { + SubnetActorDiamond subnetActor = createSubnetActor( + defaultSubnetActorParamsWith(parentGatewayAddress, parentNetworkName, tokenAddress) + ); + + return createSubnet(parentNetworkName.route, subnetActor); + } + + function createSubnet( + address[] memory subnetPath, + SubnetActorDiamond subnetActor + ) internal returns (TestSubnetDefinition memory) { + address[] memory newPath = new address[](subnetPath.length + 1); + for (uint i = 0; i < subnetPath.length; i++) { + newPath[i] = subnetPath[i]; + } + + newPath[subnetPath.length] = address(subnetActor); + + SubnetID memory subnetName = SubnetID({root: ROOTNET_CHAINID, route: newPath}); + GatewayDiamond subnetGateway = createGatewayDiamond(gatewayParams(subnetName)); + + return + TestSubnetDefinition({ + gateway: subnetGateway, + gatewayAddr: address(subnetGateway), + id: subnetName, + subnetActor: subnetActor, + subnetActorAddr: address(subnetActor), + path: newPath + }); + } + + struct Params { + RootSubnetDefinition root; + TestSubnetDefinition subnet; + TestSubnetDefinition subnetL3; + MockIpcContractResult caller; + address callerAddr; + address recipientAddr; + uint256 callerAmount; + uint256 fundAmount; + uint256 amount; + OutcomeType expectedOutcome; + bytes expectedRet; + } + + //-------------------- + // Call flow tests. + //--------------------- + + // Native supply source subnets + function testL2PlusSubnet_Native_SendCrossMessageFromChildToParentWithOkResult() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: nativeL2Subnet, + subnetL3: nativeL3Subnets[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: address(new MockIpcContractPayable()), + amount: 3, + expectedOutcome: OutcomeType.Ok, + expectedRet: abi.encode(EMPTY_BYTES), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromChildToParentWithResult(params); + } + + function testL2PlusSubnet_Native_SendCrossMessageFromParentToChildWithOkResult() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: nativeL2Subnet, + subnetL3: nativeL3Subnets[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: address(new MockIpcContractPayable()), + amount: 3, + expectedOutcome: OutcomeType.Ok, + expectedRet: abi.encode(EMPTY_BYTES), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromParentToChildWithResult(params); + } + + function testL2PlusSubnet_Native_SendCrossMessageFromSiblingToSiblingWithOkResult() public { + sendCrossMessageFromSiblingToSiblingWithOkResult(rootNetwork, nativeL2Subnet, nativeL3Subnets); + } + + // Token supply source subnets + function testL2PlusSubnet_Token_SendCrossMessageFromChildToParentWithOkResult() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: tokenL2Subnet, + subnetL3: nativeL3SubnetsWithTokenParent[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: address(new MockIpcContractPayable()), + amount: 3, + expectedOutcome: OutcomeType.Ok, + expectedRet: abi.encode(EMPTY_BYTES), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromChildToParentWithResult(params); + } + + function testL2PlusSubnet_Token_SendCrossMessageFromParentToChildWithOkResult() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: tokenL2Subnet, + subnetL3: nativeL3SubnetsWithTokenParent[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: address(new MockIpcContractPayable()), + amount: 3, + expectedOutcome: OutcomeType.Ok, + expectedRet: abi.encode(EMPTY_BYTES), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromParentToChildWithResult(params); + } + + function testL2PlusSubnet_Token_SendCrossMessageFromSiblingToSiblingWithOkResult() public { + sendCrossMessageFromSiblingToSiblingWithOkResult(rootNetwork, tokenL2Subnet, nativeL3SubnetsWithTokenParent); + } + + function testL2PlusSubnet_TokenMixed_SendCrossMessageFromSiblingToSiblingWithOkResult() public { + sendCrossMessageFromSiblingToSiblingWithOkResult(rootNetwork, tokenL2Subnet, tokenL3SubnetsWithTokenParent); + } + + // Error scenarios + function testL2PlusSubnet_Native_SendCrossMessageFromChildToNonExistingActorError() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: nativeL2Subnet, + subnetL3: nativeL3Subnets[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: 0x53c82507aA03B1a6e695000c302674ef1ecb880B, + amount: 3, + expectedOutcome: OutcomeType.ActorErr, + expectedRet: abi.encodeWithSelector(InvalidSubnetActor.selector), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromChildToParentWithResult(params); + } + + function testL2PlusSubnet_Token_SendCrossMessageFromChildToNonExistingActorError() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: tokenL2Subnet, + subnetL3: nativeL3SubnetsWithTokenParent[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: 0x53c82507aA03B1a6e695000c302674ef1ecb880B, + amount: 3, + expectedOutcome: OutcomeType.ActorErr, + expectedRet: abi.encodeWithSelector(InvalidSubnetActor.selector), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromChildToParentWithResult(params); + } + + function testL2PlusSubnet_Native_SendCrossMessageFromParentToNonExistingActorError() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: nativeL2Subnet, + subnetL3: nativeL3Subnets[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: 0x53c82507aA03B1a6e695000c302674ef1ecb880B, + amount: 3, + expectedOutcome: OutcomeType.ActorErr, + expectedRet: abi.encodeWithSelector(InvalidSubnetActor.selector), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromParentToChildWithResult(params); + } + + function testL2PlusSubnet_Token_SendCrossMessageFromParentToNonExistingActorError() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: tokenL2Subnet, + subnetL3: nativeL3SubnetsWithTokenParent[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: 0x53c82507aA03B1a6e695000c302674ef1ecb880B, + amount: 3, + expectedOutcome: OutcomeType.ActorErr, + expectedRet: abi.encodeWithSelector(InvalidSubnetActor.selector), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + sendCrossMessageFromParentToChildWithResult(params); + } + + function testL2PlusSubnet_ParentToChildTopDownNoncePropagatedCorrectly() public { + MockIpcContractResult caller = new MockIpcContractResult(); + Params memory params = Params({ + root: rootNetwork, + subnet: nativeL2Subnet, + subnetL3: nativeL3Subnets[0], + caller: caller, + callerAddr: address(caller), + recipientAddr: address(new MockIpcContractPayable()), + amount: 3, + expectedOutcome: OutcomeType.Ok, + expectedRet: abi.encode(EMPTY_BYTES), + callerAmount: 1 ether, + fundAmount: 100000 + }); + + // register L2 into root network + registerSubnet(params.subnet.subnetActorAddr, params.root.gateway); + // register L3 into L2 subnet + registerSubnet(params.subnetL3.subnetActorAddr, params.subnet.gateway); + + vm.deal(params.callerAddr, params.callerAmount); + + IpcEnvelope memory fundCrossMessage = CrossMsgHelper.createFundMsg({ + subnet: params.subnet.id, + signer: params.callerAddr, + to: FvmAddressHelper.from(params.callerAddr), + value: params.amount + }); + + // 0 is default but we set it explicitly here to make it clear + fundCrossMessage.localNonce = 0; + + vm.prank(params.callerAddr); + vm.expectEmit(true, true, true, true, params.root.gatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: params.subnet.subnetActorAddr, + message: fundCrossMessage, + id: fundCrossMessage.toTracingId() + }); + + params.root.gateway.manager().fund{value: params.amount}( + params.subnet.id, + FvmAddressHelper.from(params.callerAddr) + ); + + IpcEnvelope memory callCrossMessage = TestUtils.newXnetCallMsg( + IPCAddress({subnetId: params.root.id, rawAddress: FvmAddressHelper.from(params.callerAddr)}), + IPCAddress({subnetId: params.subnetL3.id, rawAddress: FvmAddressHelper.from(params.recipientAddr)}), + params.amount, + 1 + ); + + // send the cross message from the root network to the L3 subnet + vm.prank(params.callerAddr); + vm.expectEmit(true, true, true, true, params.root.gatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: params.subnet.subnetActorAddr, + message: callCrossMessage, + id: callCrossMessage.toTracingId() + }); + + params.root.gateway.messenger().sendContractXnetMessage{value: params.amount}(callCrossMessage); + (, uint64 rootTopDownNonce) = params.root.gateway.getter().getTopDownNonce(params.subnet.id); + assertEq(rootTopDownNonce, 2, "wrong root top down nonce"); + + IpcEnvelope[] memory msgsForL2 = new IpcEnvelope[](2); + msgsForL2[0] = fundCrossMessage; + msgsForL2[1] = callCrossMessage; + + // the expected nonce for the top down message for L3 subnet is 0 because no previous message was sent + // from L2 to L3 + msgsForL2[1].localNonce = 0; + vm.prank(FilAddress.SYSTEM_ACTOR); + vm.expectEmit(true, true, true, true, params.subnet.gatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: params.subnetL3.subnetActorAddr, + message: callCrossMessage, + id: callCrossMessage.toTracingId() + }); + + // nonce needs to be 1 because of the fund message. + msgsForL2[1].localNonce = 1; + params.subnet.gateway.xnetMessenger().applyCrossMessages(msgsForL2); + + uint64 subnetAppliedTopDownNonce = params.subnet.gateway.getter().appliedTopDownNonce(); + assertEq(subnetAppliedTopDownNonce, 2, "wrong L2 subnet applied top down nonce"); + + IpcEnvelope[] memory msgsForL3 = new IpcEnvelope[](1); + msgsForL3[0] = callCrossMessage; + + vm.prank(FilAddress.SYSTEM_ACTOR); + // nonce is zero because this is a first message touching the L3 subnet + msgsForL3[0].localNonce = 0; + params.subnetL3.gateway.xnetMessenger().applyCrossMessages(msgsForL3); + + uint64 subnetL3AppliedTopDownNonce = params.subnetL3.gateway.getter().appliedTopDownNonce(); + assertEq(subnetL3AppliedTopDownNonce, 1, "wrong L3 subnet applied top down nonce"); + + // now fund from L2 to L3 to check to nonce propagation + vm.deal(params.callerAddr, params.callerAmount); + + IpcEnvelope memory fundCrossMessageL3 = CrossMsgHelper.createFundMsg({ + subnet: params.subnetL3.id, + signer: params.callerAddr, + to: FvmAddressHelper.from(params.callerAddr), + value: params.amount + }); + + // nonce should be 1 because this is the first cross message from L1 to L3 + fundCrossMessageL3.localNonce = 1; + + vm.prank(params.callerAddr); + vm.expectEmit(true, true, true, true, params.subnet.gatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: params.subnetL3.subnetActorAddr, + message: fundCrossMessageL3, + id: fundCrossMessageL3.toTracingId() + }); + + params.subnet.gateway.manager().fund{value: params.amount}( + params.subnetL3.id, + FvmAddressHelper.from(params.callerAddr) + ); + + uint64 subnetL3AppliedTopDownNonceAfterFund = params.subnetL3.gateway.getter().appliedTopDownNonce(); + assertEq(subnetL3AppliedTopDownNonceAfterFund, 1, "wrong L3 subnet applied top down nonce"); + } + + function fundSubnet( + GatewayDiamond gateway, + TestSubnetDefinition memory subnet, + address callerAddr, + uint256 amount + ) internal { + Asset memory subnetSupply = subnet.subnetActor.getter().supplySource(); + if (subnetSupply.kind == AssetKind.ERC20) { + IERC20(subnetSupply.tokenAddress).approve(address(gateway), amount); + gateway.manager().fundWithToken(subnet.id, FvmAddressHelper.from(callerAddr), amount); + } else { + gateway.manager().fund{value: amount}(subnet.id, FvmAddressHelper.from(callerAddr)); + } + } + + function registerSubnet(address subnetActorAddr, GatewayDiamond gateway) internal { + vm.deal(subnetActorAddr, DEFAULT_COLLATERAL_AMOUNT); + vm.prank(subnetActorAddr); + registerSubnetGW(DEFAULT_COLLATERAL_AMOUNT, subnetActorAddr, gateway); + vm.stopPrank(); + } + + function sendCrossMessageFromChildToParentWithResult(Params memory params) public { + // register L2 into root nerwork + registerSubnet(params.subnet.subnetActorAddr, params.root.gateway); + // register L3 into L2 subnet + registerSubnet(params.subnetL3.subnetActorAddr, params.subnet.gateway); + + vm.deal(params.callerAddr, params.callerAmount); + vm.prank(params.callerAddr); + + fundSubnet(params.root.gateway, params.subnet, params.callerAddr, params.fundAmount); + fundSubnet(params.subnet.gateway, params.subnetL3, params.callerAddr, params.fundAmount); + + // create the xnet message on the subnet L3 - it's local gateway + IpcEnvelope memory crossMessage = TestUtils.newXnetCallMsg( + IPCAddress({subnetId: params.subnetL3.id, rawAddress: FvmAddressHelper.from(params.callerAddr)}), + IPCAddress({subnetId: params.root.id, rawAddress: FvmAddressHelper.from(params.recipientAddr)}), + params.amount, + 0 + ); + + vm.prank(params.callerAddr); + params.subnetL3.gateway.messenger().sendContractXnetMessage{value: params.amount}(crossMessage); + + // this would normally submitted by releayer. It call the subnet actor on the L2 network. + submitBottomUpCheckpoint( + callCreateBottomUpCheckpointFromChildSubnet(params.subnetL3.id, params.subnetL3.gateway), + params.subnetL3.subnetActor + ); + + // create checkpoint in L2 and submit it to the root network (L2 subnet actor) + BottomUpCheckpoint memory checkpoint = callCreateBottomUpCheckpointFromChildSubnet( + params.subnet.id, + params.subnet.gateway + ); + + // expected result top down message from root to L2. This is a response to the xnet call. + IpcEnvelope memory resultMessage = crossMessage.createResultMsg(params.expectedOutcome, params.expectedRet); + resultMessage.localNonce = 1; + + submitBottomUpCheckpointAndExpectTopDownMessageEvent( + checkpoint, + params.subnet.subnetActor, + resultMessage, + params.subnet.subnetActorAddr, + params.root.gatewayAddr + ); + + // apply the result message in the L2 subnet and expect another top down message to be emitted + IpcEnvelope[] memory msgs = new IpcEnvelope[](1); + msgs[0] = cloneIpcEnvelopeWithDifferentNonce(resultMessage, 0); + + commitParentFinality(params.subnet.gatewayAddr); + executeTopDownMsgsAndExpectTopDownMessageEvent( + msgs, + params.subnet.gateway, + resultMessage, + params.subnetL3.subnetActorAddr, + params.subnet.gatewayAddr + ); + + // apply the result and check it was propagated to the correct actor + commitParentFinality(params.subnetL3.gatewayAddr); + executeTopDownMsgs(msgs, params.subnetL3.gateway); + + assertTrue(params.caller.hasResult(), "missing result"); + assertTrue(params.caller.result().outcome == params.expectedOutcome, "wrong result outcome"); + assertTrue(keccak256(params.caller.result().ret) == keccak256(params.expectedRet), "wrong result outcome"); + } + + function sendCrossMessageFromParentToChildWithResult(Params memory params) public { + // register L2 into root network + registerSubnet(params.subnet.subnetActorAddr, params.root.gateway); + // register L3 into L2 subnet + registerSubnet(params.subnetL3.subnetActorAddr, params.subnet.gateway); + + vm.deal(params.callerAddr, params.callerAmount); + vm.prank(params.callerAddr); + + fundSubnet(params.root.gateway, params.subnet, params.callerAddr, params.fundAmount); + + IpcEnvelope memory crossMessage = TestUtils.newXnetCallMsg( + IPCAddress({subnetId: params.root.id, rawAddress: FvmAddressHelper.from(params.callerAddr)}), + IPCAddress({subnetId: params.subnetL3.id, rawAddress: FvmAddressHelper.from(params.recipientAddr)}), + params.amount, + 0 + ); + + Asset memory subnetSupply = params.subnet.subnetActor.getter().supplySource(); + + if (subnetSupply.kind == AssetKind.ERC20) { + // increase callerAddr's token balance + IERC20(subnetSupply.tokenAddress).transfer(params.callerAddr, params.amount); + // increase allowance so that send xnet msg will make it + vm.prank(params.callerAddr); + IERC20(subnetSupply.tokenAddress).approve(address(params.root.gatewayAddr), params.amount); + } + + crossMessage.localNonce = 1; + // send the cross message from the root network to the L3 subnet + vm.prank(params.callerAddr); + vm.expectEmit(true, true, true, true, params.root.gatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: params.subnet.subnetActorAddr, + message: crossMessage, + id: crossMessage.toTracingId() + }); + + crossMessage.localNonce = 0; + if (subnetSupply.kind == AssetKind.ERC20) { + params.root.gateway.messenger().sendContractXnetMessage(crossMessage); + } else { + params.root.gateway.messenger().sendContractXnetMessage{value: params.amount}(crossMessage); + } + + IpcEnvelope[] memory msgs = new IpcEnvelope[](1); + msgs[0] = crossMessage; + + // propagate the message from the L2 to the L3 subnet + executeTopDownMsgsAndExpectTopDownMessageEvent( + msgs, + params.subnet.gateway, + crossMessage, + params.subnetL3.subnetActorAddr, + params.subnet.gatewayAddr + ); + // apply the cross message in the L3 subnet + executeTopDownMsgs(msgs, params.subnetL3.gateway); + // submit checkoint so the result message can be propagated to L2 + submitBottomUpCheckpoint( + callCreateBottomUpCheckpointFromChildSubnet(params.subnetL3.id, params.subnetL3.gateway), + params.subnetL3.subnetActor + ); + // submit checkoint so the result message can be propagated to root network + submitBottomUpCheckpoint( + callCreateBottomUpCheckpointFromChildSubnet(params.subnet.id, params.subnet.gateway), + params.subnet.subnetActor + ); + assertTrue(params.caller.hasResult(), "missing result"); + assertTrue(params.caller.result().outcome == params.expectedOutcome, "wrong result outcome"); + assertTrue(keccak256(params.caller.result().ret) == keccak256(params.expectedRet), "wrong result outcome"); + } + + function sendCrossMessageFromSiblingToSiblingWithOkResult( + RootSubnetDefinition memory root, + TestSubnetDefinition memory subnet, + TestSubnetDefinition[] memory subnetL3s + ) public { + MockIpcContractResult caller = new MockIpcContractResult(); + address callerAddr = address(caller); + address recipientAddr = address(new MockIpcContract()); + uint256 amount = 3; + + vm.deal(callerAddr, 1 ether); + + // register L2 into root nerwork + registerSubnet(subnet.subnetActorAddr, root.gateway); + + // register L3s into L2 subnet + for (uint256 i; i < subnetL3s.length; i++) { + registerSubnet(subnetL3s[i].subnetActorAddr, subnet.gateway); + } + + // fund account in the L3-0 subnet + vm.prank(callerAddr); + + fundSubnet(subnet.gateway, subnetL3s[0], callerAddr, 100000); + + // create the xnet message to send fund from L3-0 to L3-1 + IpcEnvelope memory crossMessage = TestUtils.newXnetCallMsg( + IPCAddress({subnetId: subnetL3s[0].id, rawAddress: FvmAddressHelper.from(callerAddr)}), + IPCAddress({subnetId: subnetL3s[1].id, rawAddress: FvmAddressHelper.from(recipientAddr)}), + amount, + 0 + ); + + vm.prank(callerAddr); + subnetL3s[0].gateway.messenger().sendContractXnetMessage{value: amount}(crossMessage); + + // submit the checkpoint from L3-0 to L2 + BottomUpCheckpoint memory checkpoint = callCreateBottomUpCheckpointFromChildSubnet( + subnetL3s[0].id, + subnetL3s[0].gateway + ); + + // submit the checkpoint in L2 produces top down message to L3-1 + submitBottomUpCheckpointAndExpectTopDownMessageEvent( + checkpoint, + subnetL3s[0].subnetActor, + crossMessage, + subnetL3s[1].subnetActorAddr, + subnet.gatewayAddr + ); + + // mimics the execution of the top down messages in the L3-1 subnet + IpcEnvelope[] memory msgs = new IpcEnvelope[](1); + msgs[0] = crossMessage; + + executeTopDownMsgs(msgs, subnetL3s[1].gateway); + + // submit the checkpoint from L3-1 to L2 for result propagation + BottomUpCheckpoint memory resultCheckpoint = callCreateBottomUpCheckpointFromChildSubnet( + subnetL3s[1].id, + subnetL3s[1].gateway + ); + + // expected result top down message from L2 to L3. This is a response to the xnet call. + IpcEnvelope memory resultMessage = crossMessage.createResultMsg(OutcomeType.Ok, abi.encode(EMPTY_BYTES)); + resultMessage.localNonce = 1; + + // submit the checkpoint in L2 produces top down message to L3-1 + submitBottomUpCheckpointAndExpectTopDownMessageEvent( + resultCheckpoint, + subnetL3s[1].subnetActor, + resultMessage, + subnetL3s[0].subnetActorAddr, + subnet.gatewayAddr + ); + + // apply the result message in the L3-1 subnet + resultMessage.localNonce = 0; + IpcEnvelope[] memory resultMsgs = new IpcEnvelope[](1); + resultMsgs[0] = resultMessage; + + executeTopDownMsgs(resultMsgs, subnetL3s[0].gateway); + assertTrue(caller.hasResult(), "missing result"); + assertTrue(caller.result().outcome == OutcomeType.Ok, "wrong result outcome"); + } + + function commitParentFinality(address gateway) internal { + vm.roll(10); + ParentFinality memory finality = ParentFinality({height: block.number, blockHash: bytes32(0)}); + + TopDownFinalityFacet gwTopDownFinalityFacet = TopDownFinalityFacet(address(gateway)); + + vm.prank(FilAddress.SYSTEM_ACTOR); + gwTopDownFinalityFacet.commitParentFinality(finality); + } + + function executeTopDownMsgs(IpcEnvelope[] memory msgs, GatewayDiamond gw) internal { + uint256 minted_tokens; + + for (uint256 i; i < msgs.length; ) { + minted_tokens += msgs[i].value; + unchecked { + ++i; + } + } + console.log("minted tokens in executed top-downs: %d", minted_tokens); + + // The implementation of the function in fendermint is in + // https://github.com/consensus-shipyard/ipc/blob/main/fendermint/vm/interpreter/contracts/fvm/topdown.rs#L43 + + // This emulates minting tokens. + vm.deal(address(gw), minted_tokens); + + vm.prank(FilAddress.SYSTEM_ACTOR); + XnetMessagingFacet xnetMessenger = gw.xnetMessenger(); + xnetMessenger.applyCrossMessages(msgs); + } + + function executeTopDownMsgsAndExpectTopDownMessageEvent( + IpcEnvelope[] memory msgs, + GatewayDiamond gw, + IpcEnvelope memory expectedMessage, + address expectedSubnetAddr, + address expectedGatewayAddr + ) internal { + uint256 minted_tokens; + + for (uint256 i; i < msgs.length; ) { + minted_tokens += msgs[i].value; + unchecked { + ++i; + } + } + console.log("minted tokens in executed top-downs: %d", minted_tokens); + + // The implementation of the function in fendermint is in + // https://github.com/consensus-shipyard/ipc/blob/main/fendermint/vm/interpreter/contracts/fvm/topdown.rs#L43 + + // This emulates minting tokens. + vm.deal(address(gw), minted_tokens); + + vm.prank(FilAddress.SYSTEM_ACTOR); + vm.expectEmit(true, true, true, true, expectedGatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: expectedSubnetAddr, + message: expectedMessage, + id: expectedMessage.toTracingId() + }); + XnetMessagingFacet xnetMessenger = gw.xnetMessenger(); + xnetMessenger.applyCrossMessages(msgs); + } + + function callCreateBottomUpCheckpointFromChildSubnet( + SubnetID memory subnet, + GatewayDiamond gw + ) internal returns (BottomUpCheckpoint memory checkpoint) { + uint256 e = getNextEpoch(block.number, DEFAULT_CHECKPOINT_PERIOD); + + GatewayGetterFacet getter = gw.getter(); + CheckpointingFacet checkpointer = gw.checkpointer(); + + BottomUpMsgBatch memory batch = getter.bottomUpMsgBatch(e); + require(batch.msgs.length == 1, "batch length incorrect"); + + (, address[] memory addrs, uint256[] memory weights) = TestUtils.getFourValidators(vm); + + (bytes32 membershipRoot, ) = MerkleTreeHelper.createMerkleProofsForValidators(addrs, weights); + + checkpoint = BottomUpCheckpoint({ + subnetID: subnet, + blockHeight: batch.blockHeight, + blockHash: keccak256("block1"), + nextConfigurationNumber: 0, + msgs: batch.msgs, + activity: ActivityHelper.newCompressedActivityRollup(1, 3, bytes32(uint256(0))) + }); + + vm.startPrank(FilAddress.SYSTEM_ACTOR); + checkpointer.createBottomUpCheckpoint( + checkpoint, + membershipRoot, + weights[0] + weights[1] + weights[2], + ActivityHelper.dummyActivityRollup() + ); + vm.stopPrank(); + + return checkpoint; + } + + function callCreateBottomUpCheckpointFromChildSubnet( + SubnetID memory subnet, + GatewayDiamond gw, + IpcEnvelope[] memory msgs + ) internal returns (BottomUpCheckpoint memory checkpoint) { + uint256 e = getNextEpoch(block.number, DEFAULT_CHECKPOINT_PERIOD); + + CheckpointingFacet checkpointer = gw.checkpointer(); + + (, address[] memory addrs, uint256[] memory weights) = TestUtils.getFourValidators(vm); + + (bytes32 membershipRoot, ) = MerkleTreeHelper.createMerkleProofsForValidators(addrs, weights); + + checkpoint = BottomUpCheckpoint({ + subnetID: subnet, + blockHeight: e, + blockHash: keccak256("block1"), + nextConfigurationNumber: 0, + msgs: msgs, + activity: ActivityHelper.newCompressedActivityRollup(1, 3, bytes32(uint256(0))) + }); + + vm.startPrank(FilAddress.SYSTEM_ACTOR); + checkpointer.createBottomUpCheckpoint( + checkpoint, + membershipRoot, + weights[0] + weights[1] + weights[2], + ActivityHelper.dummyActivityRollup() + ); + vm.stopPrank(); + + return checkpoint; + } + + function prepareValidatorsSignatures( + BottomUpCheckpoint memory checkpoint, + SubnetActorDiamond sa + ) internal returns (address[] memory, bytes[] memory) { + (uint256[] memory parentKeys, address[] memory parentValidators, ) = TestUtils.getThreeValidators(vm); + bytes[] memory parentPubKeys = new bytes[](3); + bytes[] memory parentSignatures = new bytes[](3); + + SubnetActorManagerFacet manager = sa.manager(); + + for (uint256 i = 0; i < 3; i++) { + vm.deal(parentValidators[i], 10 gwei); + parentPubKeys[i] = TestUtils.deriveValidatorPubKeyBytes(parentKeys[i]); + vm.prank(parentValidators[i]); + manager.join{value: 10}(parentPubKeys[i], 10); + } + + bytes32 hash = keccak256(abi.encode(checkpoint)); + + for (uint256 i = 0; i < 3; i++) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(parentKeys[i], hash); + parentSignatures[i] = abi.encodePacked(r, s, v); + } + + return (parentValidators, parentSignatures); + } + + function submitBottomUpCheckpoint(BottomUpCheckpoint memory checkpoint, SubnetActorDiamond sa) internal { + (address[] memory parentValidators, bytes[] memory parentSignatures) = prepareValidatorsSignatures( + checkpoint, + sa + ); + + SubnetActorCheckpointingFacet checkpointer = sa.checkpointer(); + + vm.startPrank(address(sa)); + checkpointer.submitCheckpoint(checkpoint, parentValidators, parentSignatures); + vm.stopPrank(); + } + + function submitBottomUpCheckpointAndExpectTopDownMessageEvent( + BottomUpCheckpoint memory checkpoint, + SubnetActorDiamond subnetActor, + IpcEnvelope memory expectedMessage, + address expectedSubnetAddr, + address expectedGatewayAddr + ) internal { + (address[] memory parentValidators, bytes[] memory parentSignatures) = prepareValidatorsSignatures( + checkpoint, + subnetActor + ); + + SubnetActorCheckpointingFacet checkpointer = subnetActor.checkpointer(); + + vm.startPrank(address(subnetActor)); + vm.expectEmit(true, true, true, true, expectedGatewayAddr); + emit LibGateway.NewTopDownMessage({ + subnet: expectedSubnetAddr, + message: expectedMessage, + id: expectedMessage.toTracingId() + }); + checkpointer.submitCheckpoint(checkpoint, parentValidators, parentSignatures); + vm.stopPrank(); + } + + function submitBottomUpCheckpointRevert(BottomUpCheckpoint memory checkpoint, SubnetActorDiamond sa) internal { + vm.expectRevert(); + submitBottomUpCheckpoint(checkpoint, sa); + } + + function getNextEpoch(uint256 blockNumber, uint256 checkPeriod) internal pure returns (uint256) { + return ((uint64(blockNumber) / checkPeriod) + 1) * checkPeriod; + } + + function cloneIpcEnvelopeWithDifferentNonce( + IpcEnvelope memory original, + uint64 newNonce + ) internal pure returns (IpcEnvelope memory) { + return + IpcEnvelope({ + kind: original.kind, + to: original.to, + from: original.from, + localNonce: newNonce, + originalNonce: 0, + value: original.value, + message: original.message + }); + } + + function printActors() internal view { + console.log("root name: %s", rootNetwork.id.toString()); + console.log("root gateway: %s", rootNetwork.gatewayAddr); + console.log("root actor: %s", rootNetwork.id.getActor()); + console.log("--------------------"); + + console.log("native L2 subnet name: %s", nativeL2Subnet.id.toString()); + console.log("native L2 subnet gateway: %s", nativeL2Subnet.gatewayAddr); + console.log("native L2 subnet actor: %s", (nativeL2Subnet.subnetActorAddr)); + + for (uint256 i; i < nativeL3Subnets.length; i++) { + console.log("--------------------"); + console.log("native L3-%d subnet name: %s", i, nativeL3Subnets[i].id.toString()); + console.log("native L3-%d subnet gateway: %s", i, nativeL3Subnets[i].gatewayAddr); + console.log("native L3-%d subnet actor: %s", i, (nativeL3Subnets[i].subnetActorAddr)); + } + + for (uint256 i; i < nativeL3SubnetsWithTokenParent.length; i++) { + console.log("--------------------"); + console.log( + "native L3-%d subnet with token parent name: %s", + i, + nativeL3SubnetsWithTokenParent[i].id.toString() + ); + console.log( + "native L3-%d subnet with token parent gateway: %s", + i, + nativeL3SubnetsWithTokenParent[i].gatewayAddr + ); + console.log( + "native L3-%d subnet with token parent actor: %s", + i, + (nativeL3SubnetsWithTokenParent[i].subnetActorAddr) + ); + } + } +} diff --git a/contracts/test/integration/L2PlusXNet.t.sol b/contracts/test/integration/L2PlusXNet.t.sol new file mode 100644 index 000000000..f896adba2 --- /dev/null +++ b/contracts/test/integration/L2PlusXNet.t.sol @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.23; + +import "forge-std/Test.sol"; +import "../../contracts/errors/IPCErrors.sol"; +import {IpcEnvelope, BottomUpMsgBatch, BottomUpCheckpoint, ParentFinality, IpcMsgKind, ResultMsg} from "../../contracts/structs/CrossNet.sol"; +import {SubnetID, Subnet, IPCAddress, Validator, FvmAddress} 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} from "../../contracts/GatewayDiamond.sol"; +import {SubnetActorDiamond} from "../../contracts/SubnetActorDiamond.sol"; +import {SubnetActorManagerFacet} from "../../contracts/subnet/SubnetActorManagerFacet.sol"; +import {SubnetActorCheckpointingFacet} from "../../contracts/subnet/SubnetActorCheckpointingFacet.sol"; +import {GatewayGetterFacet} from "../../contracts/gateway/GatewayGetterFacet.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 {IntegrationTestBase, RootSubnetDefinition, TestSubnetDefinition} from "../IntegrationTestBase.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 {ActivityHelper} from "../helpers/ActivityHelper.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {ISubnetActor} from "../../contracts/interfaces/ISubnetActor.sol"; +import {IPCMsgType} from "../../contracts/enums/IPCMsgType.sol"; +import {IIpcHandler} from "../../sdk/interfaces/IIpcHandler.sol"; +import {IGateway} from "../../contracts/interfaces/IGateway.sol"; + +import "forge-std/console.sol"; + +struct SubnetsHierarchy { + /// @dev The lookup key to l1 SubnetNode + bytes32 l1NodeLookupKey; + /// @dev The lookup keys to the children and beyond + EnumerableSet.Bytes32Set subnetKeys; + mapping(address => bytes32) actorToLookupKeys; + mapping(bytes32 => SubnetNode) nodes; + mapping(bytes32 => SubnetDefinition) definitions; +} + +struct SubnetDefinition { + address gatewayAddr; + SubnetID id; +} + +struct SubnetNode { + /// @dev The list of child subnet actor address + EnumerableSet.AddressSet childActors; +} + +struct SubnetCreationParams { + SubnetID parent; + Asset supplySource; +} + +library LibSubnetsHierarchy { + using EnumerableSet for EnumerableSet.AddressSet; + using SubnetIDHelper for SubnetID; + + function initL1(SubnetsHierarchy storage self, SubnetDefinition memory l1) internal { + bytes32 lookupId = l1.id.toHash(); + + self.l1NodeLookupKey = lookupId; + storeNewNode(self, lookupId, l1.id, l1.gatewayAddr); + } + + function getSubnetGateway(SubnetsHierarchy storage self, SubnetID memory id) internal view returns (address) { + bytes32 lookupId = id.toHash(); + return getSubnetGateway(self, lookupId); + } + + function getSubnetGateway(SubnetsHierarchy storage self, bytes32 lookupId) internal view returns (address) { + require(self.definitions[lookupId].gatewayAddr != address(0), "subnet not found"); + return self.definitions[lookupId].gatewayAddr; + } + + function storeNewNode( + SubnetsHierarchy storage self, + bytes32 lookupId, + SubnetID memory id, + address gateway + ) internal { + self.definitions[lookupId].gatewayAddr = gateway; + self.definitions[lookupId].id = id; + } + + function linkNewChild(SubnetsHierarchy storage self, bytes32 lookupId, address subnetActor) internal { + self.nodes[lookupId].childActors.add(subnetActor); + } + + function registerNewSubnet( + SubnetsHierarchy storage self, + SubnetID memory parent, + address subnetActor, + address gateway + ) internal returns (SubnetID memory) { + // ensure parent exists + getSubnetGateway(self, parent); + + SubnetID memory child = SubnetIDHelper.createSubnetId(parent, subnetActor); + + bytes32 lookupId = child.toHash(); + + self.actorToLookupKeys[subnetActor] = lookupId; + storeNewNode(self, lookupId, child, gateway); + linkNewChild(self, lookupId, subnetActor); + + return child; + } + + function getGatewayBySubnetActor( + SubnetsHierarchy storage self, + address subnetActor + ) internal view returns (address) { + bytes32 lookupId = self.actorToLookupKeys[subnetActor]; + return getSubnetGateway(self, lookupId); + } +} + +contract L2PlusSubnetTest is Test, IntegrationTestBase, IIpcHandler { + using SubnetIDHelper for SubnetID; + using CrossMsgHelper for IpcEnvelope; + using GatewayFacetsHelper for GatewayDiamond; + using SubnetActorFacetsHelper for SubnetActorDiamond; + using AssetHelper for Asset; + using FvmAddressHelper for FvmAddress; + + using LibSubnetsHierarchy for SubnetsHierarchy; + + SubnetsHierarchy private subnets; + bytes32 private new_topdown_message_topic; + /// @dev The latest result message received from sending a cross network message + bytes private latestResultMessage; + + function setUp() public override { + // there seems no auto way to derive the abi in string, check this before running tests, make sure + // it's updated with the implementation + new_topdown_message_topic = keccak256( + "NewTopDownMessage(address,(uint8,((uint64,address[]),(uint8,bytes)),((uint64,address[]),(uint8,bytes)),uint64,uint256,bytes,uint64),bytes32)" + ); + + // get some free money. + vm.deal(address(this), 10 ether); + } + + // ======= implements ipc handler ======= + + /* solhint-disable-next-line unused-vars */ + function handleIpcMessage(IpcEnvelope calldata envelope) external payable returns (bytes memory ret) { + if (envelope.kind == IpcMsgKind.Result) { + latestResultMessage = envelope.message; + } + ret = bytes(""); + } + + receive() external payable {} + + // ======= internal util methods ======== + + function executeTopdownMessages(IpcEnvelope[] memory msgs, GatewayDiamond gw) internal { + uint256 mintedTokens; + + for (uint256 i; i < msgs.length; i++) { + mintedTokens += msgs[i].value; + } + console.log("minted tokens in executed top-downs: %d", mintedTokens); + + // The implementation of the function in fendermint is in + // https://github.com/consensus-shipyard/ipc/blob/main/fendermint/vm/interpreter/contracts/fvm/topdown.rs#L43 + + // This emulates minting tokens. + vm.deal(address(gw), mintedTokens); + + XnetMessagingFacet xnetMessenger = gw.xnetMessenger(); + + vm.prank(FilAddress.SYSTEM_ACTOR); + xnetMessenger.applyCrossMessages(msgs); + } + + function createBottomUpCheckpoint( + SubnetID memory subnet, + GatewayDiamond gw + ) internal returns (BottomUpCheckpoint memory checkpoint) { + uint256 e = getNextEpoch(block.number, DEFAULT_CHECKPOINT_PERIOD); + + GatewayGetterFacet getter = gw.getter(); + CheckpointingFacet checkpointer = gw.checkpointer(); + + BottomUpMsgBatch memory batch = getter.bottomUpMsgBatch(e); + + (, address[] memory addrs, uint256[] memory weights) = TestUtils.getFourValidators(vm); + + (bytes32 membershipRoot, ) = MerkleTreeHelper.createMerkleProofsForValidators(addrs, weights); + + checkpoint = BottomUpCheckpoint({ + subnetID: subnet, + blockHeight: batch.blockHeight, + blockHash: keccak256("block1"), + nextConfigurationNumber: 0, + msgs: batch.msgs, + activity: ActivityHelper.newCompressedActivityRollup(1, 3, bytes32(uint256(0))) + }); + + vm.prank(FilAddress.SYSTEM_ACTOR); + checkpointer.createBottomUpCheckpoint( + checkpoint, + membershipRoot, + weights[0] + weights[1] + weights[2], + ActivityHelper.dummyActivityRollup() + ); + + return checkpoint; + } + + function prepareValidatorsSignatures( + BottomUpCheckpoint memory checkpoint, + SubnetActorDiamond sa + ) internal returns (address[] memory, bytes[] memory) { + (uint256[] memory parentKeys, address[] memory parentValidators, ) = TestUtils.getThreeValidators(vm); + bytes[] memory parentPubKeys = new bytes[](3); + bytes[] memory parentSignatures = new bytes[](3); + + SubnetActorManagerFacet manager = sa.manager(); + + for (uint256 i = 0; i < 3; i++) { + vm.deal(parentValidators[i], 10 gwei); + parentPubKeys[i] = TestUtils.deriveValidatorPubKeyBytes(parentKeys[i]); + vm.prank(parentValidators[i]); + manager.join{value: 10}(parentPubKeys[i], 10); + } + + bytes32 hash = keccak256(abi.encode(checkpoint)); + + for (uint256 i = 0; i < 3; i++) { + (uint8 v, bytes32 r, bytes32 s) = vm.sign(parentKeys[i], hash); + parentSignatures[i] = abi.encodePacked(r, s, v); + } + + return (parentValidators, parentSignatures); + } + + function submitBottomUpCheckpoint(BottomUpCheckpoint memory checkpoint, SubnetActorDiamond sa) internal { + (address[] memory parentValidators, bytes[] memory parentSignatures) = prepareValidatorsSignatures( + checkpoint, + sa + ); + + SubnetActorCheckpointingFacet checkpointer = sa.checkpointer(); + + vm.deal(address(1), 1 ether); + vm.prank(address(1)); + checkpointer.submitCheckpoint(checkpoint, parentValidators, parentSignatures); + } + + function getNextEpoch(uint256 blockNumber, uint256 checkPeriod) internal pure returns (uint256) { + return ((uint64(blockNumber) / checkPeriod) + 1) * checkPeriod; + } + + function createNativeSubnet( + address parentGatewayAddress, + SubnetID memory parentNetworkName + ) internal returns (TestSubnetDefinition memory) { + SubnetActorDiamond subnetActor = createSubnetActor( + defaultSubnetActorParamsWith(parentGatewayAddress, parentNetworkName) + ); + + return createSubnet(parentNetworkName.route, subnetActor); + } + + function createTokenSubnet( + address tokenAddress, + address parentGatewayAddress, + SubnetID memory parentNetworkName + ) internal returns (TestSubnetDefinition memory) { + SubnetActorDiamond subnetActor = createSubnetActor( + defaultSubnetActorParamsWith(parentGatewayAddress, parentNetworkName, tokenAddress) + ); + + return createSubnet(parentNetworkName.route, subnetActor); + } + + function createSubnet( + address[] memory subnetPath, + SubnetActorDiamond subnetActor + ) internal returns (TestSubnetDefinition memory) { + address[] memory newPath = new address[](subnetPath.length + 1); + for (uint i = 0; i < subnetPath.length; i++) { + newPath[i] = subnetPath[i]; + } + + newPath[subnetPath.length] = address(subnetActor); + + SubnetID memory subnetName = SubnetID({root: ROOTNET_CHAINID, route: newPath}); + GatewayDiamond subnetGateway = createGatewayDiamond(gatewayParams(subnetName)); + + return + TestSubnetDefinition({ + gateway: subnetGateway, + gatewayAddr: address(subnetGateway), + id: subnetName, + subnetActor: subnetActor, + subnetActorAddr: address(subnetActor), + path: newPath + }); + } + + function call(IpcEnvelope memory xnetMsg) internal { + IPCMsgType msgType = xnetMsg.applyType(xnetMsg.from.subnetId); + + address gateway = subnets.getSubnetGateway(xnetMsg.from.subnetId); + vm.prank(xnetMsg.from.rawAddress.extractEvmAddress()); + + if (msgType == IPCMsgType.BottomUp) { + IGateway(gateway).sendContractXnetMessage{value: xnetMsg.value}(xnetMsg); + } else { + IGateway(gateway).sendContractXnetMessage(xnetMsg); + } + } + + function fundContract( + SubnetID memory originSubnet, + SubnetID memory targetSubnet, + address targetRecipient, + uint256 amount + ) internal { + (bool sameChain, SubnetID memory nextHop) = targetSubnet.down(originSubnet); + require(sameChain, "not in the same hierachy"); + + Asset memory supplySource = ISubnetActor(nextHop.getActor()).supplySource(); + address gateway = subnets.getSubnetGateway(originSubnet); + + vm.prank(address(this)); + supplySource.makeAvailable(gateway, amount); + + // sadly fund/fundWithToken does not support multi hierachy call, need to use xnet msg + IpcEnvelope memory crossMessage = TestUtils.newXnetCallMsg( + IPCAddress({subnetId: originSubnet, rawAddress: FvmAddressHelper.from(address(this))}), + IPCAddress({subnetId: targetSubnet, rawAddress: FvmAddressHelper.from(address(targetRecipient))}), + amount, + 0 // the nonce, does not matter, should be handled by contract calls + ); + + call(crossMessage); + } + + function initL1() internal returns (SubnetID memory) { + SubnetID memory rootNetworkName = SubnetID({root: ROOTNET_CHAINID, route: new address[](0)}); + GatewayDiamond rootGateway = createGatewayDiamond(gatewayParams(rootNetworkName)); + + SubnetDefinition memory l1Defi = SubnetDefinition({gatewayAddr: address(rootGateway), id: rootNetworkName}); + subnets.initL1(l1Defi); + + return l1Defi.id; + } + + function newSubnets(SubnetCreationParams[] memory params) internal returns (SubnetID[] memory subnetIds) { + uint256 length = params.length; + + subnetIds = new SubnetID[](length); + + for (uint256 i = 0; i < length; i++) { + address parentGateway = subnets.getSubnetGateway(params[i].parent); + + TestSubnetDefinition memory t; + if (params[i].supplySource.kind == AssetKind.Native) { + t = createNativeSubnet(parentGateway, params[i].parent); + } else { + t = createTokenSubnet(params[i].supplySource.tokenAddress, parentGateway, params[i].parent); + } + + // register child subnet to parent gateway + vm.prank(t.subnetActorAddr); + registerSubnetGW(0, t.subnetActorAddr, GatewayDiamond(payable(parentGateway))); + + subnetIds[i] = subnets.registerNewSubnet(params[i].parent, t.subnetActorAddr, t.gatewayAddr); + } + } + + function propagateUp(SubnetID memory from, SubnetID memory to) internal { + require(from.commonParent(to).equals(to), "not related subnets"); + + bool finished = false; + while (!finished) { + SubnetID memory parent = from.getParentSubnet(); + + address gateway = subnets.getSubnetGateway(from); + // this would normally submitted by releayer. It call the subnet actor on the L2 network. + submitBottomUpCheckpoint( + createBottomUpCheckpoint(from, GatewayDiamond(payable(gateway))), + SubnetActorDiamond(payable(from.getActor())) + ); + + from = parent; + finished = parent.equals(to); + } + } + + /// @dev Extracts all the NewTopdownMessage emitted events, down side is that all other events are consumed too. + function propagateDown() internal { + while (true) { + Vm.Log[] memory entries = vm.getRecordedLogs(); + + uint256 num = 0; + for (uint256 i = 0; i < entries.length; i++) { + if (entries[i].topics[0] == new_topdown_message_topic) { + IpcEnvelope[] memory msgs = new IpcEnvelope[](1); + + (IpcEnvelope memory xnetMsg, ) = abi.decode(entries[i].data, (IpcEnvelope, bytes32)); + msgs[0] = xnetMsg; + + address gateway = subnets.getGatewayBySubnetActor(address(uint160(uint256(entries[i].topics[1])))); + executeTopdownMessages(msgs, GatewayDiamond(payable(gateway))); + + num++; + } + } + + if (num == 0) { + break; + } + } + } + + /// @dev checks and ensures the latestResultMessage matches with expected bytes + function checkResultMessageBytes(bytes memory expected, string memory errorMessage) internal view { + ResultMsg memory message = abi.decode(latestResultMessage, (ResultMsg)); + require(keccak256(expected) == keccak256(message.ret), errorMessage); + } + + //-------------------- + // Call flow tests. + //--------------------- + + // testing Native L1 => ERC20 L2 => ERC20 L3, this supply source is not allowed + function test_N1E2E3_rejects() public { + SubnetID memory l1SubnetID = initL1(); + + address erc20_1 = address(new ERC20PresetFixedSupply("TestToken1", "TT", 21_000_000 ether, address(this))); + address erc20_2 = address(new ERC20PresetFixedSupply("TestToken2", "TT", 21_000_000 ether, address(this))); + + // define L2s + SubnetCreationParams[] memory l2Params = new SubnetCreationParams[](1); + l2Params[0] = SubnetCreationParams({parent: l1SubnetID, supplySource: AssetHelper.erc20(erc20_1)}); + SubnetID[] memory l2SubnetIDs = newSubnets(l2Params); + + // define L3s + SubnetCreationParams[] memory l3Params = new SubnetCreationParams[](1); + l3Params[0] = SubnetCreationParams({parent: l2SubnetIDs[0], supplySource: AssetHelper.erc20(erc20_2)}); + SubnetID[] memory l3SubnetIDs = newSubnets(l3Params); + + // create the recipients + MockIpcContractResult recipientContract = new MockIpcContractResult(); + + // initial conditions + require(address(recipientContract).balance == 0); + + // start recording events, if not called, propagate down will not work + vm.recordLogs(); + + uint256 originalBalance = IERC20(erc20_1).balanceOf(address(this)); + uint256 amount = 0.01 ether; + + // fund the L3 address should throw an error and triggers an result xnet message + fundContract({ + originSubnet: l1SubnetID, + targetSubnet: l3SubnetIDs[0], + targetRecipient: address(recipientContract), + amount: amount + }); + propagateDown(); + + // funds should now be locked + require(IERC20(erc20_1).balanceOf(address(this)) == originalBalance - amount, "balance should have droppped"); + + // relayer carries the bottom up checkpoint + propagateUp(l2SubnetIDs[0], l1SubnetID); + + // post xnet message conditions + uint256 postBalance = IERC20(erc20_1).balanceOf(address(this)); + require(postBalance == originalBalance, "token should be refunded"); + checkResultMessageBytes( + abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.IncompatibleSupplySource), + "result should be incompatible supply source" + ); + } + + // testing Native L1 => ERC20 L2 => Native L3 + function test_N1E2N3_works() public { + SubnetID memory l1SubnetID = initL1(); + + address erc20 = address(new ERC20PresetFixedSupply("TestToken", "TT", 21_000_000 ether, address(this))); + + // define L2s + SubnetCreationParams[] memory l2Params = new SubnetCreationParams[](1); + l2Params[0] = SubnetCreationParams({parent: l1SubnetID, supplySource: AssetHelper.erc20(erc20)}); + SubnetID[] memory l2SubnetIDs = newSubnets(l2Params); + + // define L3s + SubnetCreationParams[] memory l3Params = new SubnetCreationParams[](1); + l3Params[0] = SubnetCreationParams({parent: l2SubnetIDs[0], supplySource: AssetHelper.native()}); + SubnetID[] memory l3SubnetIDs = newSubnets(l3Params); + + // create the recipients + MockIpcContractResult recipientContract = new MockIpcContractResult(); + + // initial conditions + require(address(recipientContract).balance == 0); + + // start recording events, if not called, propagate down will not work + vm.recordLogs(); + + // fund the L3 address first + fundContract({ + originSubnet: l1SubnetID, + targetSubnet: l3SubnetIDs[0], + targetRecipient: address(recipientContract), + amount: 0.01 ether + }); + + propagateDown(); + + // post xnet message conditions + require(address(recipientContract).balance == 0.01 ether); + } + + // testing Native L3 => ERC20 L2 => Native L1 => ERC20 L2' => Native L3' + function test_N3E2N1E2N3_works() public { + SubnetID memory l1SubnetID = initL1(); + + address erc20 = address(new ERC20PresetFixedSupply("TestToken", "TT", 21_000_000 ether, address(this))); + + // define L2s + SubnetCreationParams[] memory l2Params = new SubnetCreationParams[](2); + l2Params[0] = SubnetCreationParams({parent: l1SubnetID, supplySource: AssetHelper.erc20(erc20)}); + l2Params[1] = SubnetCreationParams({parent: l1SubnetID, supplySource: AssetHelper.erc20(erc20)}); + SubnetID[] memory l2SubnetIDs = newSubnets(l2Params); + + // define L3s + SubnetCreationParams[] memory l3Params = new SubnetCreationParams[](2); + l3Params[0] = SubnetCreationParams({parent: l2SubnetIDs[0], supplySource: AssetHelper.native()}); + l3Params[1] = SubnetCreationParams({parent: l2SubnetIDs[1], supplySource: AssetHelper.native()}); + SubnetID[] memory l3SubnetIDs = newSubnets(l3Params); + + // create the sender and recipients + MockIpcContractResult callerContract = new MockIpcContractResult(); + MockIpcContractResult recipientContract = new MockIpcContractResult(); + + // start recording events, if not called, propagate down will not work + vm.recordLogs(); + + uint256 amount = 0.01 ether; + + // fund the L3 address first + fundContract({ + originSubnet: l1SubnetID, + targetSubnet: l3SubnetIDs[0], + targetRecipient: address(callerContract), + amount: amount + }); + propagateDown(); + + // initial conditions + require(address(callerContract).balance == amount, "sender initial balance should be 0.01 ether"); + require(address(recipientContract).balance == 0, "recipient initial balance should be 0"); + + // the funds now arrives at L3, trigger cross network call + IpcEnvelope memory crossMessage = TestUtils.newXnetCallMsg( + IPCAddress({subnetId: l3SubnetIDs[0], rawAddress: FvmAddressHelper.from(address(callerContract))}), + IPCAddress({subnetId: l3SubnetIDs[1], rawAddress: FvmAddressHelper.from(address(recipientContract))}), + amount, + 0 // the nonce, does not matter, should be handled by contract calls + ); + + call(crossMessage); + + propagateUp(l3SubnetIDs[0], l1SubnetID); + propagateDown(); + + // post xnet message conditions + require(address(callerContract).balance == 0, "sender final balance should be 0"); + require(address(recipientContract).balance == amount, "recipient final balance should be 0.01 ether"); + require( + address(subnets.getSubnetGateway(l3SubnetIDs[1])).balance == 0, + "L3 gateway final balance should be 0 ether" + ); + require( + address(subnets.getSubnetGateway(l3SubnetIDs[0])).balance == 0, + "L3 gateway final balance should be 0 ether" + ); + } +} diff --git a/contracts/test/integration/MultiSubnet.t.sol b/contracts/test/integration/MultiSubnet.t.sol index 53654136d..bbb8bae41 100644 --- a/contracts/test/integration/MultiSubnet.t.sol +++ b/contracts/test/integration/MultiSubnet.t.sol @@ -115,7 +115,7 @@ contract MultiSubnetTest is Test, IntegrationTestBase { address tokenAddress, address rootGatewayAddress, SubnetID memory rootSubnetName - ) internal returns (TestSubnetDefinition memory tokenSubnet) { + ) internal returns (TestSubnetDefinition memory) { SubnetActorDiamond rootTokenSubnetActor = createSubnetActor( defaultSubnetActorParamsWith(rootGatewayAddress, rootSubnetName, tokenAddress) ); @@ -124,14 +124,15 @@ contract MultiSubnetTest is Test, IntegrationTestBase { SubnetID memory tokenSubnetName = SubnetID({root: ROOTNET_CHAINID, route: tokenSubnetPath}); GatewayDiamond tokenSubnetGateway = createGatewayDiamond(gatewayParams(tokenSubnetName)); - tokenSubnet = TestSubnetDefinition({ - gateway: tokenSubnetGateway, - gatewayAddr: address(tokenSubnetGateway), - id: tokenSubnetName, - subnetActor: rootTokenSubnetActor, - subnetActorAddr: address(rootTokenSubnetActor), - path: tokenSubnetPath - }); + return + TestSubnetDefinition({ + gateway: tokenSubnetGateway, + gatewayAddr: address(tokenSubnetGateway), + id: tokenSubnetName, + subnetActor: rootTokenSubnetActor, + subnetActorAddr: address(rootTokenSubnetActor), + path: tokenSubnetPath + }); } //-------------------- @@ -158,7 +159,7 @@ contract MultiSubnetTest is Test, IntegrationTestBase { vm.prank(caller); vm.expectEmit(true, true, true, true, rootSubnet.gatewayAddr); - emit LibGateway.NewTopDownMessage(nativeSubnet.subnetActorAddr, expected); + emit LibGateway.NewTopDownMessage(nativeSubnet.subnetActorAddr, expected, expected.toTracingId()); rootSubnet.gateway.manager().fund{value: amount}(nativeSubnet.id, FvmAddressHelper.from(address(recipient))); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); @@ -287,7 +288,7 @@ contract MultiSubnetTest is Test, IntegrationTestBase { vm.prank(caller); vm.expectEmit(true, true, true, true, rootSubnet.gatewayAddr); - emit LibGateway.NewTopDownMessage(nativeSubnet.subnetActorAddr, expected); + emit LibGateway.NewTopDownMessage(nativeSubnet.subnetActorAddr, expected, expected.toTracingId()); rootSubnet.gateway.manager().fund{value: amount}(nativeSubnet.id, FvmAddressHelper.from(address(recipient))); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); @@ -324,7 +325,7 @@ contract MultiSubnetTest is Test, IntegrationTestBase { vm.prank(caller); vm.expectEmit(true, true, true, true, rootSubnet.gatewayAddr); - emit LibGateway.NewTopDownMessage(tokenSubnet.subnetActorAddr, expected); + emit LibGateway.NewTopDownMessage(tokenSubnet.subnetActorAddr, expected, expected.toTracingId()); rootSubnet.gateway.manager().fundWithToken(tokenSubnet.id, FvmAddressHelper.from(address(recipient)), amount); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); @@ -571,7 +572,7 @@ contract MultiSubnetTest is Test, IntegrationTestBase { vm.prank(caller); vm.expectEmit(true, true, true, true, rootSubnet.gatewayAddr); - emit LibGateway.NewTopDownMessage(tokenSubnet.subnetActorAddr, expected); + emit LibGateway.NewTopDownMessage(tokenSubnet.subnetActorAddr, expected, expected.toTracingId()); rootSubnet.gateway.manager().fundWithToken(tokenSubnet.id, FvmAddressHelper.from(address(recipient)), amount); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); @@ -1094,8 +1095,6 @@ contract MultiSubnetTest is Test, IntegrationTestBase { ); submitBottomUpCheckpoint(checkpoint, nativeSubnet.subnetActor); - - assertEq(recipient.balance, amount); } function testMultiSubnet_Native_SendCrossMessageFromParentToChild() public { @@ -1125,12 +1124,17 @@ contract MultiSubnetTest is Test, IntegrationTestBase { to: xnetCallMsg.to, value: xnetCallMsg.value, message: xnetCallMsg.message, - nonce: 1 + originalNonce: 0, + localNonce: 1 }); vm.prank(address(caller)); vm.expectEmit(true, true, true, true, rootSubnet.gatewayAddr); - emit LibGateway.NewTopDownMessage({subnet: nativeSubnet.subnetActorAddr, message: committedEvent}); + emit LibGateway.NewTopDownMessage({ + subnet: nativeSubnet.subnetActorAddr, + message: committedEvent, + id: committedEvent.toTracingId() + }); rootSubnet.gateway.messenger().sendContractXnetMessage{value: amount}(xnetCallMsg); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); @@ -1138,8 +1142,6 @@ contract MultiSubnetTest is Test, IntegrationTestBase { commitParentFinality(nativeSubnet.gatewayAddr); executeTopDownMsgs(msgs, nativeSubnet.id, nativeSubnet.gateway); - - assertEq(address(recipient).balance, amount); } function testMultiSubnet_Token_CallResultRevertsFromChildToParent() public { @@ -1238,8 +1240,6 @@ contract MultiSubnetTest is Test, IntegrationTestBase { ); submitBottomUpCheckpoint(checkpoint, tokenSubnet.subnetActor); - - assertEq(token.balanceOf(recipient), amount); } function testMultiSubnet_Erc20_SendCrossMessageFromParentToChild() public { @@ -1273,12 +1273,17 @@ contract MultiSubnetTest is Test, IntegrationTestBase { to: xnetCallMsg.to, value: xnetCallMsg.value, message: xnetCallMsg.message, - nonce: 1 + originalNonce: 0, + localNonce: 1 }); vm.prank(address(caller)); vm.expectEmit(true, true, true, true, rootSubnet.gatewayAddr); - emit LibGateway.NewTopDownMessage({subnet: tokenSubnet.subnetActorAddr, message: committedEvent}); + emit LibGateway.NewTopDownMessage({ + subnet: tokenSubnet.subnetActorAddr, + message: committedEvent, + id: committedEvent.toTracingId() + }); rootSubnet.gateway.messenger().sendContractXnetMessage{value: amount}(xnetCallMsg); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); @@ -1286,8 +1291,6 @@ contract MultiSubnetTest is Test, IntegrationTestBase { commitParentFinality(tokenSubnet.gatewayAddr); executeTopDownMsgs(msgs, tokenSubnet.id, tokenSubnet.gateway); - - assertEq(address(recipient).balance, amount); } function commitParentFinality(address gateway) internal { diff --git a/contracts/test/sdk/IpcContract.t.sol b/contracts/test/sdk/IpcContract.t.sol index 264675d95..acd7290c4 100644 --- a/contracts/test/sdk/IpcContract.t.sol +++ b/contracts/test/sdk/IpcContract.t.sol @@ -118,7 +118,8 @@ contract IpcExchangeTest is Test { to: ipcAddressB, value: 1000, message: abi.encode(callMsg), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); resultMsg = ResultMsg({outcome: OutcomeType.Ok, id: callEnvelope.toHash(), ret: bytes("")}); @@ -129,7 +130,8 @@ contract IpcExchangeTest is Test { to: ipcAddressA, value: 1000, message: abi.encode(resultMsg), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); exch = new RecorderIpcExchange(gateway); @@ -210,7 +212,7 @@ contract IpcExchangeTest is Test { // Send three messages from within the contract. bytes32[] memory ids = new bytes32[](3); for (uint64 i = 0; i < 3; i++) { - callEnvelope.nonce = i; + callEnvelope.localNonce = i; vm.mockCall( gateway, abi.encodeWithSelector(IGateway.sendContractXnetMessage.selector), diff --git a/contracts/test/unit/CrossMsgHelper.t.sol b/contracts/test/unit/CrossMsgHelper.t.sol index e71d0e154..114e0710e 100644 --- a/contracts/test/unit/CrossMsgHelper.t.sol +++ b/contracts/test/unit/CrossMsgHelper.t.sol @@ -8,6 +8,7 @@ import "../../contracts/lib/FvmAddressHelper.sol"; import {FvmAddress} from "../../contracts/structs/FvmAddress.sol"; import {Asset} from "../../contracts/structs/Subnet.sol"; import {IpcMsgKind, CallMsg} from "../../contracts/structs/CrossNet.sol"; +import {MockFallbackContract} from "../helpers/TestUtils.sol"; import "@openzeppelin/contracts/utils/Address.sol"; @@ -68,7 +69,7 @@ contract CrossMsgHelperTest is Test { require(releaseMsg.to.subnetId.toHash() == parentSubnetId.toHash()); require(releaseMsg.to.rawAddress.extractEvmAddress() == sender); require(releaseMsg.value == releaseAmount); - require(releaseMsg.nonce == 0); + require(releaseMsg.localNonce == 0); require(releaseMsg.message.length == 0); require(releaseMsg.kind == IpcMsgKind.Transfer); } @@ -102,7 +103,7 @@ contract CrossMsgHelperTest is Test { require(fundMsg.to.subnetId.toHash() == parentSubnetId.toHash()); require(fundMsg.to.rawAddress.extractEvmAddress() == sender); require(fundMsg.value == fundAmount); - require(fundMsg.nonce == 0); + require(fundMsg.localNonce == 0); require(fundMsg.message.length == 0); require(fundMsg.kind == IpcMsgKind.Transfer); } @@ -131,7 +132,7 @@ contract CrossMsgHelperTest is Test { require(fundMsg.to.subnetId.toHash() == subnetId.toHash()); require(fundMsg.to.rawAddress.extractEvmAddress() == sender); require(fundMsg.value == fundAmount); - require(fundMsg.nonce == 0); + require(fundMsg.localNonce == 0); require(fundMsg.kind == IpcMsgKind.Transfer); } @@ -145,7 +146,7 @@ contract CrossMsgHelperTest is Test { function test_Execute_Works_SendValue() public { address sender = address(this); - address recipient = address(100); + address recipient = address(new MockFallbackContract()); crossMsg.to.rawAddress = FvmAddressHelper.from(recipient); crossMsg.kind = IpcMsgKind.Call; @@ -159,13 +160,11 @@ contract CrossMsgHelperTest is Test { (, bytes memory result) = crossMsg.execute(AssetHelper.native()); require(keccak256(result) == keccak256(EMPTY_BYTES)); - require(recipient.balance == 1); - require(sender.balance == 1 ether - 1); } function test_Execute_Works_FunctionCallWithValue() public { address sender = address(this); - address recipient = address(100); + address recipient = address(new MockFallbackContract()); crossMsg.to.rawAddress = FvmAddressHelper.from(recipient); crossMsg.kind = IpcMsgKind.Call; @@ -178,14 +177,15 @@ contract CrossMsgHelperTest is Test { vm.deal(sender, 1 ether); vm.expectCall(recipient, crossMsg.value, new bytes(0), 1); - (, bytes memory result) = crossMsg.execute(AssetHelper.native()); + (bool ok, bytes memory result) = crossMsg.execute(AssetHelper.native()); + console.log(ok); require(keccak256(result) == keccak256(EMPTY_BYTES)); } function test_Execute_Works_FunctionCallWithoutValue() public { address sender = address(this); - address recipient = address(100); + address recipient = address(new MockFallbackContract()); crossMsg.kind = IpcMsgKind.Call; crossMsg.to.rawAddress = FvmAddressHelper.from(recipient); @@ -337,7 +337,15 @@ contract CrossMsgHelperTest is Test { uint64 nonce ) internal pure returns (IpcEnvelope memory) { return - IpcEnvelope({kind: IpcMsgKind.Transfer, from: from, to: to, value: 0, message: EMPTY_BYTES, nonce: nonce}); + IpcEnvelope({ + kind: IpcMsgKind.Transfer, + from: from, + to: to, + value: 0, + message: EMPTY_BYTES, + localNonce: nonce, + originalNonce: 0 + }); } function createCrossMsgs(uint256 length, uint64 nonce) internal pure returns (IpcEnvelope[] memory _crossMsgs) { @@ -349,7 +357,7 @@ contract CrossMsgHelperTest is Test { } function addCrossMsg(uint64 nonce) internal { - crossMsg.nonce = nonce; + crossMsg.localNonce = nonce; crossMsgs.push(crossMsg); } diff --git a/contracts/test/unit/GenericTokenHelper.t.sol b/contracts/test/unit/GenericTokenHelper.t.sol index 1ba246c9e..280841145 100644 --- a/contracts/test/unit/GenericTokenHelper.t.sol +++ b/contracts/test/unit/GenericTokenHelper.t.sol @@ -9,6 +9,7 @@ import {Asset, AssetKind} from "../../contracts/structs/Subnet.sol"; import {AssetHelper} from "../../contracts/lib/AssetHelper.sol"; import {AssetHelperMock} from "../mocks/AssetHelperMock.sol"; +import {MockFallbackContract} from "../helpers/TestUtils.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -61,6 +62,7 @@ contract AssetHelperTest is Test { uint256 balance = 1_000_000; uint256 value = 100; AssetHelperMock mock = new AssetHelperMock(); + MockFallbackContract actor = new MockFallbackContract(); IERC20 token = new ERC20PresetFixedSupply("TestToken", "TEST", balance, address(mock)); @@ -68,27 +70,29 @@ contract AssetHelperTest is Test { bytes memory params = bytes("hello"); - mock.performCall(source, payable(address(1)), params, value); + mock.performCall(source, payable(address(actor)), params, value); require(token.balanceOf(address(mock)) == balance - value, "invalid balance"); - require(token.balanceOf(address(1)) == value, "invalid user balance"); + require(token.balanceOf(address(actor)) == value, "invalid user balance"); } function test_call_with_native_zero_balance_ok() public { uint256 value = 0; AssetHelperMock mock = new AssetHelperMock(); + MockFallbackContract actor = new MockFallbackContract(); Asset memory source = Asset({kind: AssetKind.Native, tokenAddress: address(0)}); bytes memory params = bytes("hello"); - mock.performCall(source, payable(address(1)), params, value); - require(address(1).balance == 0, "invalid user balance"); + mock.performCall(source, payable(address(actor)), params, value); + require(address(actor).balance == 0, "invalid user balance"); } function test_call_with_native_ok() public { uint256 value = 10; AssetHelperMock mock = new AssetHelperMock(); + MockFallbackContract actor = new MockFallbackContract(); vm.deal(address(mock), 1 ether); @@ -96,8 +100,10 @@ contract AssetHelperTest is Test { bytes memory params = bytes("hello"); - mock.performCall(source, payable(address(1)), params, value); - require(address(1).balance == value, "invalid user balance"); + mock.performCall(source, payable(address(actor)), params, value); + + console.log("actor balance", address(actor).balance); + require(address(actor).balance == value, "invalid user balance"); } function test_call_with_native_reverts() public { diff --git a/contracts/test/unit/LibGateway.t.sol b/contracts/test/unit/LibGateway.t.sol index adc498a24..8a200d226 100644 --- a/contracts/test/unit/LibGateway.t.sol +++ b/contracts/test/unit/LibGateway.t.sol @@ -38,7 +38,8 @@ contract LibGatewayTest is Test { to: IPCAddress({subnetId: subnetId, rawAddress: FvmAddressHelper.from(address(2))}), value: 0, message: new bytes(0), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); vm.recordLogs(); @@ -60,7 +61,8 @@ contract LibGatewayTest is Test { to: IPCAddress({subnetId: subnetId, rawAddress: FvmAddressHelper.from(address(2))}), value: 0, message: new bytes(0), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); t.applyMsg(subnetId, envelope); @@ -99,11 +101,11 @@ contract LibGatewayTest is Test { method: GatewayDummyContract.reverts.selector, params: new bytes(0) }); - crossMsg.nonce = 0; + crossMsg.localNonce = 0; ResultMsg memory message = ResultMsg({ outcome: OutcomeType.Ok, - id: crossMsg.toHash(), + id: crossMsg.toTracingId(), ret: abi.encode(EMPTY_BYTES) }); IpcEnvelope memory expected = IpcEnvelope({ @@ -112,11 +114,12 @@ contract LibGatewayTest is Test { to: crossMsg.from, value: 0, // it succeeded message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); vm.expectEmit(address(t)); - emit LibGateway.NewTopDownMessage(childSubnetActor, expected); + emit LibGateway.NewTopDownMessage(childSubnetActor, expected, expected.toTracingId()); t.applyMsg(childSubnet, crossMsg); } @@ -153,11 +156,11 @@ contract LibGatewayTest is Test { method: bytes4(0), params: new bytes(0) }); - crossMsg.nonce = 0; + crossMsg.localNonce = 0; ResultMsg memory message = ResultMsg({ outcome: OutcomeType.Ok, - id: crossMsg.toHash(), + id: crossMsg.toTracingId(), ret: abi.encode(EMPTY_BYTES) }); IpcEnvelope memory expected = IpcEnvelope({ @@ -166,7 +169,8 @@ contract LibGatewayTest is Test { to: crossMsg.from, value: 0, // it succeeded message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); t.applyMsg(parentSubnet, crossMsg); @@ -198,30 +202,30 @@ contract LibGatewayTest is Test { address fromRaw = address(1000); address toRaw = address(1001); - IPCAddress memory from = IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}); - IPCAddress memory to = IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(toRaw)}); + uint256 value = 1000; IpcEnvelope memory crossMsg = CrossMsgHelper.createCallMsg({ - from: from, - to: to, - value: 1000, + from: IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}), + to: IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(toRaw)}), + value: value, method: bytes4(0), params: new bytes(0) }); - crossMsg.nonce = 10; // a wrong nonce + crossMsg.localNonce = 10; // a wrong nonce ResultMsg memory message = ResultMsg({ outcome: OutcomeType.SystemErr, - id: crossMsg.toHash(), + id: crossMsg.toTracingId(), ret: abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.Nonce) }); IpcEnvelope memory expected = IpcEnvelope({ kind: IpcMsgKind.Result, from: crossMsg.to, to: crossMsg.from, - value: crossMsg.value, + value: value, message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); t.applyMsg(parentSubnet, crossMsg); @@ -264,16 +268,21 @@ contract LibGatewayTest is Test { method: GatewayDummyContract.reverts.selector, params: new bytes(0) }); - crossMsg.nonce = 0; + crossMsg.localNonce = 0; - ResultMsg memory message = ResultMsg({outcome: OutcomeType.ActorErr, id: crossMsg.toHash(), ret: new bytes(0)}); + ResultMsg memory message = ResultMsg({ + outcome: OutcomeType.ActorErr, + id: crossMsg.toTracingId(), + ret: new bytes(0) + }); IpcEnvelope memory expected = IpcEnvelope({ kind: IpcMsgKind.Result, from: crossMsg.to, to: crossMsg.from, value: 0, message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); t.applyMsg(parentSubnet, crossMsg); @@ -285,43 +294,6 @@ contract LibGatewayTest is Test { require(stored.toHash() == expected.toHash(), "receipt hash not matching"); } - function test_applyMsg_bottomUpNotRegistered() public { - LibGatewayMock t = new LibGatewayMock(); - - address callingContract = address(new GatewayDummyContract()); - - address childSubnetActor = address(new SubnetActorGetterFacet()); - - address[] memory parentRoute = new address[](1); - parentRoute[0] = address(1); - - address[] memory childRoute = new address[](2); - childRoute[0] = address(1); - childRoute[1] = childSubnetActor; - - SubnetID memory parentSubnet = SubnetID({root: 1, route: parentRoute}); - SubnetID memory childSubnet = SubnetID({root: 1, route: childRoute}); - - t.setSubnet(parentSubnet, 1); - - address fromRaw = address(1000); - address toRaw = callingContract; - - IPCAddress memory from = IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}); - IPCAddress memory to = IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(toRaw)}); - - IpcEnvelope memory crossMsg = CrossMsgHelper.createCallMsg({ - from: from, - to: to, - value: 0, - method: GatewayDummyContract.reverts.selector, - params: new bytes(0) - }); - crossMsg.nonce = 0; - - t.applyMsg(childSubnet, crossMsg); - } - function test_applyMsg_bottomUpInvalidNonce() public { LibGatewayMock t = new LibGatewayMock(); address callingContract = address(new GatewayDummyContract()); @@ -344,34 +316,34 @@ contract LibGatewayTest is Test { address fromRaw = address(1000); address toRaw = callingContract; - IPCAddress memory from = IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}); - IPCAddress memory to = IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(toRaw)}); + uint256 value = 1000; IpcEnvelope memory crossMsg = CrossMsgHelper.createCallMsg({ - from: from, - to: to, - value: 1000, + from: IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}), + to: IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(toRaw)}), + value: value, method: GatewayDummyContract.reverts.selector, params: new bytes(0) }); - crossMsg.nonce = 10; + crossMsg.localNonce = 10; ResultMsg memory message = ResultMsg({ outcome: OutcomeType.SystemErr, - id: crossMsg.toHash(), + id: crossMsg.toTracingId(), ret: abi.encodeWithSelector(InvalidXnetMessage.selector, InvalidXnetMessageReason.Nonce) }); IpcEnvelope memory expected = IpcEnvelope({ kind: IpcMsgKind.Result, from: crossMsg.to, to: crossMsg.from, - value: crossMsg.value, + value: value, message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); vm.expectEmit(address(t)); - emit LibGateway.NewTopDownMessage(childSubnetActor, expected); + emit LibGateway.NewTopDownMessage(childSubnetActor, expected, expected.toTracingId()); t.applyMsg(childSubnet, crossMsg); } @@ -398,31 +370,35 @@ contract LibGatewayTest is Test { address fromRaw = address(1000); address toRaw = callingContract; - IPCAddress memory from = IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}); - IPCAddress memory to = IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(toRaw)}); + uint256 value = 1000; IpcEnvelope memory crossMsg = CrossMsgHelper.createCallMsg({ - from: from, - to: to, - value: 1000, + from: IPCAddress({subnetId: childSubnet, rawAddress: FvmAddressHelper.from(fromRaw)}), + to: IPCAddress({subnetId: parentSubnet, rawAddress: FvmAddressHelper.from(toRaw)}), + value: value, method: GatewayDummyContract.reverts.selector, params: new bytes(0) }); - crossMsg.nonce = 0; + crossMsg.localNonce = 0; - ResultMsg memory message = ResultMsg({outcome: OutcomeType.ActorErr, id: crossMsg.toHash(), ret: new bytes(0)}); + ResultMsg memory message = ResultMsg({ + outcome: OutcomeType.ActorErr, + id: crossMsg.toTracingId(), + ret: new bytes(0) + }); IpcEnvelope memory expected = IpcEnvelope({ kind: IpcMsgKind.Result, from: crossMsg.to, to: crossMsg.from, - value: crossMsg.value, + value: value, message: abi.encode(message), - nonce: 0 + originalNonce: 0, + localNonce: 0 }); vm.deal(address(t), 1 ether); vm.expectEmit(address(t)); - emit LibGateway.NewTopDownMessage(childSubnetActor, expected); + emit LibGateway.NewTopDownMessage(childSubnetActor, expected, expected.toTracingId()); t.applyMsg(childSubnet, crossMsg); } diff --git a/contracts/test/unit/SubnetIDHelper.t.sol b/contracts/test/unit/SubnetIDHelper.t.sol index 68a32bacb..99028d588 100644 --- a/contracts/test/unit/SubnetIDHelper.t.sol +++ b/contracts/test/unit/SubnetIDHelper.t.sol @@ -121,8 +121,11 @@ contract SubnetIDHelperTest is Test { route3[1] = SUBNET_THREE_ADDRESS; SubnetID memory subnetId3 = SubnetID(ROOTNET_CHAINID, route3); - require(subnetId2.down(subnetId1).equals(subnetId2)); - require(subnetId3.down(subnetId1).equals(subnetId2)); + (, SubnetID memory down1) = subnetId2.down(subnetId1); + require(down1.equals(subnetId2)); + + (, SubnetID memory down2) = subnetId3.down(subnetId1); + require(down2.equals(subnetId2)); } function test_Down_Works_Subnet2RouteLengthLargerThanSubnet1() public { @@ -133,8 +136,9 @@ contract SubnetIDHelperTest is Test { SubnetID memory subnetId1 = SubnetID(ROOTNET_CHAINID, route1); SubnetID memory subnetId2 = SubnetID(ROOTNET_CHAINID, route2); - vm.expectRevert(SubnetIDHelper.InvalidRoute.selector); - subnetId1.down(subnetId2); + (bool foundDown, SubnetID memory down) = subnetId1.down(subnetId2); + assertFalse(foundDown); + assertTrue(down.isEmpty()); } function test_Down_Works_Subnet2RouteLenghtEqualToSubnet1() public { @@ -147,16 +151,18 @@ contract SubnetIDHelperTest is Test { SubnetID memory subnetId1 = SubnetID(ROOTNET_CHAINID, route1); SubnetID memory subnetId2 = SubnetID(ROOTNET_CHAINID, route2); - vm.expectRevert(SubnetIDHelper.InvalidRoute.selector); - subnetId1.down(subnetId2); + (bool foundDown, SubnetID memory down) = subnetId1.down(subnetId2); + assertFalse(foundDown); + assertTrue(down.isEmpty()); } function test_Down_Works_WrongRoot() public { SubnetID memory subnetId1 = SubnetID(1, new address[](0)); SubnetID memory subnetId2 = SubnetID(2, new address[](0)); - vm.expectRevert(SubnetIDHelper.DifferentRootNetwork.selector); - subnetId1.down(subnetId2); + (bool foundDown, SubnetID memory down) = subnetId1.down(subnetId2); + assertFalse(foundDown); + assertTrue(down.isEmpty()); } function test_Down_Works_CommonRootParent() public view { @@ -170,7 +176,7 @@ contract SubnetIDHelperTest is Test { SubnetID memory subnetId1 = SubnetID(ROOTNET_CHAINID, subnetRoute1); SubnetID memory subnetId2 = SubnetID(ROOTNET_CHAINID, subnetRoute2); - SubnetID memory subnetId = subnetId1.down(subnetId2); + (, SubnetID memory subnetId) = subnetId1.down(subnetId2); require(subnetId.toHash() == ROOT_SUBNET_ID.createSubnetId(subnetRoute1[0]).toHash()); } @@ -189,7 +195,7 @@ contract SubnetIDHelperTest is Test { SubnetID memory subnetId1 = SubnetID(ROOTNET_CHAINID, subnetRoute1); SubnetID memory subnetId2 = SubnetID(ROOTNET_CHAINID, subnetRoute2); - SubnetID memory subnetId = subnetId1.down(subnetId2); + (, SubnetID memory subnetId) = subnetId1.down(subnetId2); address[] memory expectedRoute = new address[](3); expectedRoute[0] = address(100); diff --git a/extras/linked-token/contracts/LinkedToken.sol b/extras/linked-token/contracts/LinkedToken.sol index 5f6d8100a..7245d5f4a 100644 --- a/extras/linked-token/contracts/LinkedToken.sol +++ b/extras/linked-token/contracts/LinkedToken.sol @@ -140,7 +140,7 @@ abstract contract LinkedToken is Initializable, IpcExchangeUpgradeable { sender: msg.sender, recipient: recipient, id: committed.toHash(), - nonce: committed.nonce, + nonce: committed.localNonce, value: amount }); } diff --git a/extras/linked-token/test/LinkedTokenController.t.sol b/extras/linked-token/test/LinkedTokenController.t.sol index 475c79b79..3bccdc9e2 100644 --- a/extras/linked-token/test/LinkedTokenController.t.sol +++ b/extras/linked-token/test/LinkedTokenController.t.sol @@ -107,7 +107,8 @@ contract LinkedTokenControllerTest is Test, IntegrationTestBase { from: IPCAddress({subnetId: replicaSubnetName, rawAddress: FvmAddressHelper.from(address(controller))}), to: IPCAddress({subnetId: controllerSubnet, rawAddress: FvmAddressHelper.from(address(replica))}), value: DEFAULT_CROSS_MSG_FEE, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: abi.encode(message) }); @@ -119,7 +120,8 @@ contract LinkedTokenControllerTest is Test, IntegrationTestBase { }), to: IPCAddress({subnetId: controllerSubnet, rawAddress: FvmAddressHelper.from(address(replica))}), value: DEFAULT_CROSS_MSG_FEE, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: abi.encode(message) }); @@ -131,7 +133,8 @@ contract LinkedTokenControllerTest is Test, IntegrationTestBase { }), to: IPCAddress({subnetId: controllerSubnet, rawAddress: FvmAddressHelper.from(address(replica))}), value: DEFAULT_CROSS_MSG_FEE, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: abi.encode(message) }); diff --git a/extras/linked-token/test/LinkedTokenReplica.t.sol b/extras/linked-token/test/LinkedTokenReplica.t.sol index 20bb3180b..a2696ca66 100644 --- a/extras/linked-token/test/LinkedTokenReplica.t.sol +++ b/extras/linked-token/test/LinkedTokenReplica.t.sol @@ -104,7 +104,8 @@ contract LinkedTokenReplicaTest is Test, IntegrationTestBase { from: IPCAddress({subnetId: controllerSubnet, rawAddress: FvmAddressHelper.from(address(controller))}), to: IPCAddress({subnetId: replicaSubnetName, rawAddress: FvmAddressHelper.from(address(replica))}), value: DEFAULT_CROSS_MSG_FEE, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: abi.encode(message) }); @@ -113,7 +114,8 @@ contract LinkedTokenReplicaTest is Test, IntegrationTestBase { from: IPCAddress({subnetId: controllerSubnet, rawAddress: FvmAddressHelper.from(address(replica))}), to: IPCAddress({subnetId: replicaSubnetName, rawAddress: FvmAddressHelper.from(address(replica))}), value: DEFAULT_CROSS_MSG_FEE, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: abi.encode(message) }); @@ -122,7 +124,8 @@ contract LinkedTokenReplicaTest is Test, IntegrationTestBase { from: IPCAddress({subnetId: replicaSubnetName, rawAddress: FvmAddressHelper.from(address(replica))}), to: IPCAddress({subnetId: replicaSubnetName, rawAddress: FvmAddressHelper.from(address(controller))}), value: DEFAULT_CROSS_MSG_FEE, - nonce: 0, + localNonce: 0, + originalNonce: 0, message: abi.encode(message) }); diff --git a/extras/linked-token/test/MultiSubnetTest.t.sol b/extras/linked-token/test/MultiSubnetTest.t.sol index 8b421d7e3..67aa84313 100644 --- a/extras/linked-token/test/MultiSubnetTest.t.sol +++ b/extras/linked-token/test/MultiSubnetTest.t.sol @@ -184,7 +184,7 @@ contract MultiSubnetTest is IntegrationTestBase { ipcTokenReplica.setLinkedContract(address(ipcTokenController)); } - function testMultiSubnet_Native_FundFromParentToChild_USDCBridge() public { + function testMultiSubnet_Native_FundFromParentToChild_USDCBridgeBaisc() public { _testLinkedTokenBridge(); } @@ -291,7 +291,8 @@ contract MultiSubnetTest is IntegrationTestBase { to: lockAndTransferEnvelope.to, value: 0, message: lockAndTransferEnvelope.message, - nonce: 0 // nonce will be updated by LibGateway.commitCrossMessage + originalNonce: 0, + localNonce: 0 // localNonce will be updated by LibGateway.commitCrossMessage }); IpcEnvelope[] memory msgs = new IpcEnvelope[](1); diff --git a/fendermint/testing/contract-test/tests/smt_staking.rs b/fendermint/testing/contract-test/tests/smt_staking.rs index 9e0f27ec7..5b25892be 100644 --- a/fendermint/testing/contract-test/tests/smt_staking.rs +++ b/fendermint/testing/contract-test/tests/smt_staking.rs @@ -70,7 +70,8 @@ fn prop_cross_msgs_hash() { }, }, value: from_fvm::to_eth_tokens(&ArbTokenAmount::arbitrary(u)?.0).unwrap(), - nonce: u.arbitrary()?, + local_nonce: u.arbitrary()?, + original_nonce: u.arbitrary()?, // FIXME: Add arbitrary here? message: Vec::new().into(), }) diff --git a/fendermint/vm/topdown/src/finality/fetch.rs b/fendermint/vm/topdown/src/finality/fetch.rs index fb4203045..b49bf8f09 100644 --- a/fendermint/vm/topdown/src/finality/fetch.rs +++ b/fendermint/vm/topdown/src/finality/fetch.rs @@ -367,7 +367,7 @@ mod tests { TokenAmount::from_atto(100), ) .unwrap(); - msg.nonce = nonce; + msg.local_nonce = nonce; msg } diff --git a/fendermint/vm/topdown/src/finality/null.rs b/fendermint/vm/topdown/src/finality/null.rs index 9a4a7beea..755a3fd45 100644 --- a/fendermint/vm/topdown/src/finality/null.rs +++ b/fendermint/vm/topdown/src/finality/null.rs @@ -276,7 +276,7 @@ impl FinalityWithNull { if !top_down_msgs.is_empty() { // make sure incoming top down messages are ordered by nonce sequentially tracing::debug!(?top_down_msgs); - ensure_sequential(&top_down_msgs, |msg| msg.nonce)?; + ensure_sequential(&top_down_msgs, |msg| msg.local_nonce)?; }; if !validator_changes.is_empty() { tracing::debug!(?validator_changes, "validator changes"); diff --git a/fendermint/vm/topdown/src/proxy.rs b/fendermint/vm/topdown/src/proxy.rs index 94a8e3177..303b0e15c 100644 --- a/fendermint/vm/topdown/src/proxy.rs +++ b/fendermint/vm/topdown/src/proxy.rs @@ -96,7 +96,7 @@ impl ParentQueryProxy for IPCProviderProxy { .await .map(|mut v| { // sort ascending, we dont assume the changes are ordered - v.value.sort_by(|a, b| a.nonce.cmp(&b.nonce)); + v.value.sort_by(|a, b| a.local_nonce.cmp(&b.local_nonce)); v }) } diff --git a/ipc/api/src/cross.rs b/ipc/api/src/cross.rs index 6c3e70b39..d69d8ac94 100644 --- a/ipc/api/src/cross.rs +++ b/ipc/api/src/cross.rs @@ -32,7 +32,9 @@ pub struct IpcEnvelope { pub message: Vec, /// outgoing nonce for the envelope. /// This nonce is set by the gateway when committing the message for propagation - pub nonce: u64, + pub local_nonce: u64, + /// original nonce of the message from the source network + pub original_nonce: u64, } impl IpcEnvelope { @@ -56,7 +58,8 @@ impl IpcEnvelope { from, to, value, - nonce: 0, + local_nonce: 0, + original_nonce: 0, message: Default::default(), }) } @@ -82,7 +85,8 @@ impl IpcEnvelope { from, to, value, - nonce: 0, + local_nonce: 0, + original_nonce: 0, message: Default::default(), }) } diff --git a/ipc/api/src/evm.rs b/ipc/api/src/evm.rs index d19a853a3..ae721459f 100644 --- a/ipc/api/src/evm.rs +++ b/ipc/api/src/evm.rs @@ -94,7 +94,8 @@ macro_rules! cross_msg_types { to: $module::Ipcaddress::try_from(value.to) .map_err(|e| anyhow!("cannot convert `to`` ipc address due to: {e:}"))?, value: val, - nonce: value.nonce, + local_nonce: value.local_nonce, + original_nonce: value.original_nonce, message: ethers::core::types::Bytes::from(value.message), }; Ok(c) @@ -111,7 +112,8 @@ macro_rules! cross_msg_types { value: eth_to_fil_amount(&value.value)?, kind: IpcMsgKind::try_from(value.kind)?, message: value.message.to_vec(), - nonce: value.nonce, + local_nonce: value.local_nonce, + original_nonce: value.original_nonce, }; Ok(s) } diff --git a/ipc/cli/src/commands/crossmsg/topdown_cross.rs b/ipc/cli/src/commands/crossmsg/topdown_cross.rs index 3e100bc84..78d5c583e 100644 --- a/ipc/cli/src/commands/crossmsg/topdown_cross.rs +++ b/ipc/cli/src/commands/crossmsg/topdown_cross.rs @@ -40,7 +40,7 @@ impl CommandLineHandler for ListTopdownMsgs { msg.from.to_string()?, msg.to.to_string()?, hex::encode(msg.message), - msg.nonce + msg.local_nonce ); } } diff --git a/ipc/provider/src/lib.rs b/ipc/provider/src/lib.rs index 862a40cbe..f9a34dceb 100644 --- a/ipc/provider/src/lib.rs +++ b/ipc/provider/src/lib.rs @@ -527,19 +527,6 @@ impl IpcProvider { .await } - /// Propagate a cross-net message forward. For `postbox_msg_key`, we are using bytes because different - /// runtime have different representations. For FVM, it should be `CID` as bytes. For EVM, it is - /// `bytes32`. - pub async fn propagate( - &self, - _subnet: SubnetID, - _gateway_addr: Address, - _from: Address, - _postbox_msg_key: Vec, - ) -> anyhow::Result<()> { - todo!() - } - /// Send value between two addresses in a subnet pub async fn send_value( &mut self, diff --git a/ipc/provider/src/manager/evm/manager.rs b/ipc/provider/src/manager/evm/manager.rs index 46e3228e3..28d180948 100644 --- a/ipc/provider/src/manager/evm/manager.rs +++ b/ipc/provider/src/manager/evm/manager.rs @@ -8,10 +8,10 @@ use std::time::Duration; use ethers_contract::{ContractError, EthLogDecode, LogMeta}; use ipc_actors_abis::{ - checkpointing_facet, gateway_getter_facet, gateway_manager_facet, gateway_messenger_facet, - lib_gateway, lib_quorum, lib_staking_change_log, register_subnet_facet, - subnet_actor_activity_facet, subnet_actor_checkpointing_facet, subnet_actor_getter_facet, - subnet_actor_manager_facet, subnet_actor_reward_facet, + checkpointing_facet, gateway_getter_facet, gateway_manager_facet, lib_gateway, lib_quorum, + lib_staking_change_log, register_subnet_facet, subnet_actor_activity_facet, + subnet_actor_checkpointing_facet, subnet_actor_getter_facet, subnet_actor_manager_facet, + subnet_actor_reward_facet, }; use ipc_api::evm::{fil_to_eth_amount, payload_to_evm_address, subnet_id_to_evm_addresses}; use ipc_api::validator::from_contract_validators; @@ -673,42 +673,6 @@ impl SubnetManager for EthSubnetManager { block_number_from_receipt(receipt) } - /// Propagate the postbox message key. The key should be `bytes32`. - async fn propagate( - &self, - _subnet: SubnetID, - gateway_addr: Address, - from: Address, - postbox_msg_key: Vec, - ) -> Result<()> { - if postbox_msg_key.len() != 32 { - return Err(anyhow!( - "invalid message cid length, expect 32 but found {}", - postbox_msg_key.len() - )); - } - - self.ensure_same_gateway(&gateway_addr)?; - - tracing::info!("propagate postbox evm gateway contract: {gateway_addr:} with message key: {postbox_msg_key:?}"); - - let signer = Arc::new(self.get_signer_with_fee_estimator(&from)?); - let gateway_contract = gateway_messenger_facet::GatewayMessengerFacet::new( - self.ipc_contract_info.gateway_addr, - signer.clone(), - ); - - let mut key = [0u8; 32]; - key.copy_from_slice(&postbox_msg_key); - - extend_call_with_pending_block(gateway_contract.propagate(key)) - .await? - .send() - .await?; - - Ok(()) - } - /// Send value between two addresses in a subnet async fn send_value(&self, from: Address, to: Address, amount: TokenAmount) -> Result<()> { let signer = Arc::new(self.get_signer_with_fee_estimator(&from)?); diff --git a/ipc/provider/src/manager/subnet.rs b/ipc/provider/src/manager/subnet.rs index d7715550e..d87fbe2c5 100644 --- a/ipc/provider/src/manager/subnet.rs +++ b/ipc/provider/src/manager/subnet.rs @@ -140,17 +140,6 @@ pub trait SubnetManager: amount: TokenAmount, ) -> Result; - /// Propagate a cross-net message forward. For `postbox_msg_key`, we are using bytes because different - /// runtime have different representations. For FVM, it should be `CID` as bytes. For EVM, it is - /// `bytes32`. - async fn propagate( - &self, - subnet: SubnetID, - gateway_addr: Address, - from: Address, - postbox_msg_key: Vec, - ) -> Result<()>; - /// Send value between two addresses in a subnet async fn send_value(&self, from: Address, to: Address, amount: TokenAmount) -> Result<()>;