-
Notifications
You must be signed in to change notification settings - Fork 196
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 support for upgrading systems #1378
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
"@latticexyz/world": minor | ||
--- | ||
|
||
It is now possible to upgrade systems by calling `registerSystem` again with an existing system id (resource selector). | ||
|
||
```solidity | ||
// Register a system | ||
world.registerSystem(systemId, systemAddress, publicAccess); | ||
|
||
// Upgrade the system by calling `registerSystem` with the | ||
// same system id but a new system address or publicAccess flag | ||
world.registerSystem(systemId, newSystemAddress, newPublicAccess); | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,27 +62,46 @@ contract WorldRegistrationSystem is System, IWorldErrors { | |
* If the namespace doesn't exist yet, it is registered. | ||
* The system is granted access to its namespace, so it can write to any table in the same namespace. | ||
* If publicAccess is true, no access control check is performed for calling the system. | ||
* | ||
* Note: this function doesn't check whether a system already exists at the given selector, | ||
* making it possible to upgrade systems. | ||
*/ | ||
function registerSystem(bytes32 resourceSelector, WorldContextConsumer system, bool publicAccess) public virtual { | ||
// Require the name to not be the namespace's root name | ||
if (resourceSelector.getName() == ROOT_NAME) revert InvalidSelector(resourceSelector.toString()); | ||
|
||
// Require the system to not exist yet | ||
if (SystemRegistry.get(address(system)) != 0) revert SystemExists(address(system)); | ||
// Require this system to not be registered at a different resource selector yet | ||
bytes32 existingResourceSelector = SystemRegistry.get(address(system)); | ||
if (existingResourceSelector != 0 && existingResourceSelector != resourceSelector) { | ||
revert SystemExists(address(system)); | ||
} | ||
|
||
// If the namespace doesn't exist yet, register it | ||
// otherwise require caller to own the namespace | ||
bytes16 namespace = resourceSelector.getNamespace(); | ||
if (ResourceType.get(namespace) == Resource.NONE) registerNamespace(namespace); | ||
else AccessControl.requireOwnerOrSelf(namespace, _msgSender()); | ||
|
||
// Require no resource to exist at this selector yet | ||
if (ResourceType.get(resourceSelector) != Resource.NONE) { | ||
// Require no resource other than a system to exist at this selector yet | ||
Resource resourceType = ResourceType.get(resourceSelector); | ||
if (resourceType != Resource.NONE && resourceType != Resource.SYSTEM) { | ||
revert ResourceExists(resourceSelector.toString()); | ||
} | ||
|
||
// Store the system resource type | ||
ResourceType.set(resourceSelector, Resource.SYSTEM); | ||
// Check if a system already exists at this resource selector | ||
address existingSystem = Systems.getSystem(resourceSelector); | ||
|
||
// If there is an existing system with this resource selector, remove it | ||
if (existingSystem != address(0)) { | ||
// Remove the existing system from the system registry | ||
SystemRegistry.deleteRecord(existingSystem); | ||
|
||
// Remove the existing system's access to its namespace | ||
ResourceAccess.deleteRecord(namespace, existingSystem); | ||
} else { | ||
// Otherwise, this is a new system, so register its resource type | ||
ResourceType.set(resourceSelector, Resource.SYSTEM); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. idle thought: I wonder if it's worth encoding the resource type into the selector, so selectors become something like
this would save a little on storage (but maybe not in any meaningful way if it's only used during registration) and could help during introspection (it's part of the selector/identifier itself rather than a separate lookup) (Stripe has this for all IDs where each ID has a prefix of the kind of entity it is, e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree that might make sense! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. opened an issue here: #1394 |
||
|
||
// Systems = mapping from resourceSelector to system address and publicAccess | ||
Systems.set(resourceSelector, address(system), publicAccess); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooc why? what if I want the same system in multiple namespaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since access control is based on addresses that would be a security risk (namespace A might have given system X access, now you register system X in namespace B without realising it might mean whoever has access to the system based on namespace A can now also call the system to access namespace B)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm, interesting! should we do access based on selector instead of/in addition to address?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since access control is also used for EOAs it couldn't be in instead of address (since EOAs don't have a registered selector). It would probably be possible to have an additional concept of access control based on the selector, but there are more complexities: if a system is registered at two selectors, it's not possible to infer the selector based on the system address (since there is no 1-1 mapping anymore), so a system would have to provide its own selector for every call that requires access control. That would require the system to be aware of where its registered (currently it doesn't care) and might have more security implications. Overall I think it's not worth the additional complexity to allow a system to be registered multiple times.