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, store): stop loading schema from storage, require schema as an argument #1174

Merged
merged 21 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/few-mirrors-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
"@latticexyz/cli": major
"@latticexyz/store": major
"@latticexyz/world": major
"create-mud": patch
---

All `Store` methods now require the table's value schema to be passed in as an argument instead of loading it from storage.
This decreases gas cost and removes circular dependencies of the Schema table (where it was not possible to write to the Schema table before the Schema table was registered).

```diff
function setRecord(
bytes32 table,
bytes32[] calldata key,
bytes calldata data,
+ Schema valueSchema
Copy link
Member

Choose a reason for hiding this comment

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

Does the argument ordering here make sense? I usually order args by specificity and would kind of expect valueSchema to be further ahead in the list of arguments (before or after table perhaps).

Unless it's an optional arg, then it being at the end makes a bit more sense.

Copy link
Member Author

Choose a reason for hiding this comment

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

i agree with ordering by specificity but would defer this refactor until after this current stack of PRs is merged since they touch lots of the same places in the code and changing it here would likely lead to massive merge conflicts in the upstream branches

) external;
```

The same diff applies to `getRecord`, `getField`, `setField`, `pushToField`, `popFromField`, `updateInField`, and `deleteRecord`.

This change only requires changes in downstream projects if the `Store` methods were accessed directly. In most cases it is fully abstracted in the generated table libraries,
so downstream projects only need to regenerate their table libraries after updating MUD.
24 changes: 12 additions & 12 deletions e2e/packages/contracts/src/codegen/tables/Multi.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0);
bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0, getSchema());
return (int256(uint256(Bytes.slice32(_blob, 0))));
}

Expand All @@ -95,7 +95,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

bytes memory _blob = _store.getField(_tableId, _keyTuple, 0);
bytes memory _blob = _store.getField(_tableId, _keyTuple, 0, getSchema());
return (int256(uint256(Bytes.slice32(_blob, 0))));
}

Expand All @@ -107,7 +107,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((num)));
StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((num)), getSchema());
}

/** Set num (using the specified store) */
Expand All @@ -118,7 +118,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

_store.setField(_tableId, _keyTuple, 0, abi.encodePacked((num)));
_store.setField(_tableId, _keyTuple, 0, abi.encodePacked((num)), getSchema());
}

/** Get value */
Expand All @@ -129,7 +129,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 1);
bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 1, getSchema());
return (_toBool(uint8(Bytes.slice1(_blob, 0))));
}

Expand All @@ -141,7 +141,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

bytes memory _blob = _store.getField(_tableId, _keyTuple, 1);
bytes memory _blob = _store.getField(_tableId, _keyTuple, 1, getSchema());
return (_toBool(uint8(Bytes.slice1(_blob, 0))));
}

Expand All @@ -153,7 +153,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

StoreSwitch.setField(_tableId, _keyTuple, 1, abi.encodePacked((value)));
StoreSwitch.setField(_tableId, _keyTuple, 1, abi.encodePacked((value)), getSchema());
}

/** Set value (using the specified store) */
Expand All @@ -164,7 +164,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

_store.setField(_tableId, _keyTuple, 1, abi.encodePacked((value)));
_store.setField(_tableId, _keyTuple, 1, abi.encodePacked((value)), getSchema());
}

/** Get the full data */
Expand Down Expand Up @@ -201,7 +201,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

StoreSwitch.setRecord(_tableId, _keyTuple, _data);
StoreSwitch.setRecord(_tableId, _keyTuple, _data, getSchema());
}

/** Set the full data using individual values (using the specified store) */
Expand All @@ -214,7 +214,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

_store.setRecord(_tableId, _keyTuple, _data);
_store.setRecord(_tableId, _keyTuple, _data, getSchema());
}

/** Set the full data using the data struct */
Expand Down Expand Up @@ -256,7 +256,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

StoreSwitch.deleteRecord(_tableId, _keyTuple);
StoreSwitch.deleteRecord(_tableId, _keyTuple, getSchema());
}

/* Delete all data for given keys (using the specified store) */
Expand All @@ -267,7 +267,7 @@ library Multi {
_keyTuple[2] = bytes32(uint256(c));
_keyTuple[3] = bytes32(uint256(int256(d)));

_store.deleteRecord(_tableId, _keyTuple);
_store.deleteRecord(_tableId, _keyTuple, getSchema());
}
}

Expand Down
12 changes: 6 additions & 6 deletions e2e/packages/contracts/src/codegen/tables/Number.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ library Number {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0);
bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0, getSchema());
return (uint32(Bytes.slice4(_blob, 0)));
}

Expand All @@ -79,7 +79,7 @@ library Number {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

bytes memory _blob = _store.getField(_tableId, _keyTuple, 0);
bytes memory _blob = _store.getField(_tableId, _keyTuple, 0, getSchema());
return (uint32(Bytes.slice4(_blob, 0)));
}

Expand All @@ -88,15 +88,15 @@ library Number {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((value)));
StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((value)), getSchema());
}

/** Set value (using the specified store) */
function set(IStore _store, uint32 key, uint32 value) internal {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

_store.setField(_tableId, _keyTuple, 0, abi.encodePacked((value)));
_store.setField(_tableId, _keyTuple, 0, abi.encodePacked((value)), getSchema());
}

/** Tightly pack full data using this table's schema */
Expand All @@ -115,14 +115,14 @@ library Number {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

StoreSwitch.deleteRecord(_tableId, _keyTuple);
StoreSwitch.deleteRecord(_tableId, _keyTuple, getSchema());
}

/* Delete all data for given keys (using the specified store) */
function deleteRecord(IStore _store, uint32 key) internal {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

_store.deleteRecord(_tableId, _keyTuple);
_store.deleteRecord(_tableId, _keyTuple, getSchema());
}
}
24 changes: 12 additions & 12 deletions e2e/packages/contracts/src/codegen/tables/NumberList.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,30 +68,30 @@ library NumberList {
function get() internal view returns (uint32[] memory value) {
bytes32[] memory _keyTuple = new bytes32[](0);

bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0);
bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0, getSchema());
return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint32());
}

/** Get value (using the specified store) */
function get(IStore _store) internal view returns (uint32[] memory value) {
bytes32[] memory _keyTuple = new bytes32[](0);

bytes memory _blob = _store.getField(_tableId, _keyTuple, 0);
bytes memory _blob = _store.getField(_tableId, _keyTuple, 0, getSchema());
return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_uint32());
}

/** Set value */
function set(uint32[] memory value) internal {
bytes32[] memory _keyTuple = new bytes32[](0);

StoreSwitch.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)));
StoreSwitch.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)), getSchema());
}

/** Set value (using the specified store) */
function set(IStore _store, uint32[] memory value) internal {
bytes32[] memory _keyTuple = new bytes32[](0);

_store.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)));
_store.setField(_tableId, _keyTuple, 0, EncodeArray.encode((value)), getSchema());
}

/** Get the length of value */
Expand Down Expand Up @@ -144,28 +144,28 @@ library NumberList {
function push(uint32 _element) internal {
bytes32[] memory _keyTuple = new bytes32[](0);

StoreSwitch.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)));
StoreSwitch.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)), getSchema());
}

/** Push an element to value (using the specified store) */
function push(IStore _store, uint32 _element) internal {
bytes32[] memory _keyTuple = new bytes32[](0);

_store.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)));
_store.pushToField(_tableId, _keyTuple, 0, abi.encodePacked((_element)), getSchema());
}

/** Pop an element from value */
function pop() internal {
bytes32[] memory _keyTuple = new bytes32[](0);

StoreSwitch.popFromField(_tableId, _keyTuple, 0, 4);
StoreSwitch.popFromField(_tableId, _keyTuple, 0, 4, getSchema());
}

/** Pop an element from value (using the specified store) */
function pop(IStore _store) internal {
bytes32[] memory _keyTuple = new bytes32[](0);

_store.popFromField(_tableId, _keyTuple, 0, 4);
_store.popFromField(_tableId, _keyTuple, 0, 4, getSchema());
}

/**
Expand All @@ -176,7 +176,7 @@ library NumberList {
bytes32[] memory _keyTuple = new bytes32[](0);

unchecked {
StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element)));
StoreSwitch.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element)), getSchema());
}
}

Expand All @@ -188,7 +188,7 @@ library NumberList {
bytes32[] memory _keyTuple = new bytes32[](0);

unchecked {
_store.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element)));
_store.updateInField(_tableId, _keyTuple, 0, _index * 4, abi.encodePacked((_element)), getSchema());
}
}

Expand All @@ -210,13 +210,13 @@ library NumberList {
function deleteRecord() internal {
bytes32[] memory _keyTuple = new bytes32[](0);

StoreSwitch.deleteRecord(_tableId, _keyTuple);
StoreSwitch.deleteRecord(_tableId, _keyTuple, getSchema());
}

/* Delete all data for given keys (using the specified store) */
function deleteRecord(IStore _store) internal {
bytes32[] memory _keyTuple = new bytes32[](0);

_store.deleteRecord(_tableId, _keyTuple);
_store.deleteRecord(_tableId, _keyTuple, getSchema());
}
}
24 changes: 12 additions & 12 deletions e2e/packages/contracts/src/codegen/tables/Vector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0);
bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0, getSchema());
return (int32(uint32(Bytes.slice4(_blob, 0))));
}

Expand All @@ -86,7 +86,7 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

bytes memory _blob = _store.getField(_tableId, _keyTuple, 0);
bytes memory _blob = _store.getField(_tableId, _keyTuple, 0, getSchema());
return (int32(uint32(Bytes.slice4(_blob, 0))));
}

Expand All @@ -95,23 +95,23 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((x)));
StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((x)), getSchema());
}

/** Set x (using the specified store) */
function setX(IStore _store, uint32 key, int32 x) internal {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

_store.setField(_tableId, _keyTuple, 0, abi.encodePacked((x)));
_store.setField(_tableId, _keyTuple, 0, abi.encodePacked((x)), getSchema());
}

/** Get y */
function getY(uint32 key) internal view returns (int32 y) {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 1);
bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 1, getSchema());
return (int32(uint32(Bytes.slice4(_blob, 0))));
}

Expand All @@ -120,7 +120,7 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

bytes memory _blob = _store.getField(_tableId, _keyTuple, 1);
bytes memory _blob = _store.getField(_tableId, _keyTuple, 1, getSchema());
return (int32(uint32(Bytes.slice4(_blob, 0))));
}

Expand All @@ -129,15 +129,15 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

StoreSwitch.setField(_tableId, _keyTuple, 1, abi.encodePacked((y)));
StoreSwitch.setField(_tableId, _keyTuple, 1, abi.encodePacked((y)), getSchema());
}

/** Set y (using the specified store) */
function setY(IStore _store, uint32 key, int32 y) internal {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

_store.setField(_tableId, _keyTuple, 1, abi.encodePacked((y)));
_store.setField(_tableId, _keyTuple, 1, abi.encodePacked((y)), getSchema());
}

/** Get the full data */
Expand Down Expand Up @@ -165,7 +165,7 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

StoreSwitch.setRecord(_tableId, _keyTuple, _data);
StoreSwitch.setRecord(_tableId, _keyTuple, _data, getSchema());
}

/** Set the full data using individual values (using the specified store) */
Expand All @@ -175,7 +175,7 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

_store.setRecord(_tableId, _keyTuple, _data);
_store.setRecord(_tableId, _keyTuple, _data, getSchema());
}

/** Set the full data using the data struct */
Expand Down Expand Up @@ -211,14 +211,14 @@ library Vector {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

StoreSwitch.deleteRecord(_tableId, _keyTuple);
StoreSwitch.deleteRecord(_tableId, _keyTuple, getSchema());
}

/* Delete all data for given keys (using the specified store) */
function deleteRecord(IStore _store, uint32 key) internal {
bytes32[] memory _keyTuple = new bytes32[](1);
_keyTuple[0] = bytes32(uint256(key));

_store.deleteRecord(_tableId, _keyTuple);
_store.deleteRecord(_tableId, _keyTuple, getSchema());
}
}
Loading
Loading