Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(world): add callFrom entry point #1364

Merged
merged 15 commits into from
Sep 1, 2023
Merged

feat(world): add callFrom entry point #1364

merged 15 commits into from
Sep 1, 2023

Conversation

alvrs
Copy link
Member

@alvrs alvrs commented Aug 25, 2023

fixes #1358
see changeset for details on this change

@changeset-bot
Copy link

changeset-bot bot commented Aug 25, 2023

🦋 Changeset detected

Latest commit: 042893f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
Name Type
@latticexyz/world Major
@latticexyz/cli Major
@latticexyz/dev-tools Major
@latticexyz/store-sync Major
@latticexyz/store-indexer Major
@latticexyz/block-logs-stream Major
@latticexyz/common Major
@latticexyz/config Major
create-mud Major
@latticexyz/ecs-browser Major
@latticexyz/gas-report Major
@latticexyz/network Major
@latticexyz/noise Major
@latticexyz/phaserx Major
@latticexyz/protocol-parser Major
@latticexyz/react Major
@latticexyz/recs Major
@latticexyz/schema-type Major
@latticexyz/services Major
@latticexyz/solecs Major
solhint-config-mud Major
solhint-plugin-mud Major
@latticexyz/std-client Major
@latticexyz/std-contracts Major
@latticexyz/store-cache Major
@latticexyz/store Major
@latticexyz/utils Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@@ -10,4 +10,5 @@ interface IWorldErrors {
error FunctionSelectorExists(bytes4 functionSelector);
error FunctionSelectorNotFound(bytes4 functionSelector);
error ModuleAlreadyInstalled(string module);
error NoDelegationFound(address grantor, address grantee);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
error NoDelegationFound(address grantor, address grantee);
error DelegationNotFound(address grantor, address grantee);

(for consistency with our other errors)

@alvrs
Copy link
Member Author

alvrs commented Aug 29, 2023

Did some refactors around Call.withSender and World._call which i'll move to a separate PR. Reason is that it's actually cheaper (and better dev ex) to call the delegation control system via its resource selector instead of storing its address, because then we can use delegatecall for delegation control checks that were registered as root systems, which makes their storage accesses cheaper.

@alvrs
Copy link
Member Author

alvrs commented Aug 30, 2023

*/
function registerDelegation(
address delegatee,
bytes32 delegationControl,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

took me a bit to realize we switched from address to resource selector/ID, and wondering if we should clarify the naming here to delegationControlId or something?

resourceSelector: resourceSelector,
funcSelectorAndArgsHash: funcSelectorAndArgsHash,
availableCalls: availableCalls - 1
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we delete once we get to zero?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be unchecked, since you do availableCalls > 0 already

import { DelegationControl } from "../../DelegationControl.sol";
import { DisposableDelegations } from "./tables/DisposableDelegations.sol";

contract DisposableDelegationControl is DelegationControl {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this better than "decaying" 👍

Another potential name idea is "callbound" (to go with "timebound")


// Set the timestamp to maxTimestamp+1 and expect the delegation to be expired
vm.warp(maxTimestamp + 1);
vm.expectRevert(abi.encodeWithSelector(IWorldErrors.DelegationNotFound.selector, delegator, delegatee));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny thing but I tend to put the expectRevert immediately before the thing we expect to revert, to not confuse this with "I expect vm.prank to revert"

holic
holic previously approved these changes Sep 1, 2023
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: MIT
Copy link
Member

@holic holic Sep 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thoughts on just delegations instead of std-delegations for the dir name?

oh nevermind, this seems to reflect the module name and these files are tied to the module

dk1a
dk1a previously approved these changes Sep 1, 2023
resourceSelector: resourceSelector,
funcSelectorAndArgsHash: funcSelectorAndArgsHash,
availableCalls: availableCalls - 1
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be unchecked, since you do availableCalls > 0 already

Comment on lines 6 to 12
bytes16 constant MODULE_NAME = bytes16("stddelegations.m");

// Disposable delegation
bytes32 constant DISPOSABLE_DELEGATION = bytes32(abi.encodePacked(ROOT_NAMESPACE, bytes16("disposable.d")));

// Timebound delegation
bytes32 constant TIMEBOUND_DELEGATION = bytes32(abi.encodePacked(ROOT_NAMESPACE, bytes16("timebound.d")));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it perhaps have a MODULE_NAMESPACE?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was that this module should ideally be installed as a root module (so it can install the systems as root systems), because it reduces the gas cost of all systems that read or change state (around 8k for the calls to DisposableDelegationSystem)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I have my head wrapped around the end-to-end, but are these delegation/callfrom checks always routed through the world? Ultimately wondering if it would be useful to inherit the namespace or allow the namespace to be configured, or if that only has negative consequences (only used by world, only more gas)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are always routed through the World. The main challenge is that the delegation check system needs to know which table to access. We could make this dynamic and store the namespace in which the module is registered in storage and then load it from storage in the system, but that would cost more gas. A cheaper alternative would be to just use two different modules for root and non-root installations (it only needs to be installed once per world, so the namespace for non-root could also be fixed). For now, I'd just go with providing the root version, because I'd expect this standard module to be installed by default - if we find there's a need for a non-root version (to be installed on worlds that don't have the root version installed by default), we can just add another version of the module later

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

root only for now as the default/expected/most common path is totally fine by me


if (availableCalls > 0) {
// Decrement the number of available calls
unchecked {
Copy link
Member

@holic holic Sep 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know the consequences of unchecked but is it safe for us to wrap this whole statement vs just the decrement? Would unchecked apply to the .set() or _msgSender() calls?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it would

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved it outside of the block, gas didn't change so seems like unchecked doesn't impact the nested calls, but fells still cleaner to have it explicit

@alvrs alvrs changed the title feat: add callFrom entry point feat(world): add callFrom entry point Sep 1, 2023
@alvrs alvrs merged commit 1ca35e9 into main Sep 1, 2023
@alvrs alvrs deleted the alvrs/call-from branch September 1, 2023 13:20
@github-actions github-actions bot mentioned this pull request Sep 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Proposal: account delegation via callFrom
3 participants