Major Changes
-
#1482
07dd6f32
Thanks @alvrs! - Renamed all occurrences ofschema
where it is used as "value schema" tovalueSchema
to clearly distinguish it from "key schema".
The only breaking change for users is the change fromschema
tovalueSchema
inmud.config.ts
.// mud.config.ts export default mudConfig({ tables: { CounterTable: { keySchema: {}, - schema: { + valueSchema: { value: "uint32", }, }, } }
-
#1354
331dbfdc
Thanks @dk1a! - We've updated Store events to be "schemaless", meaning there is enough information in each event to only need to operate on the bytes of each record to make an update to that record without having to first decode the record by its schema. This enables new kinds of indexers and sync strategies.As such, we've replaced
blockStorageOperations# @latticexyz/store-sync with
storedBlockLogs# @latticexyz/store-sync, a stream of simplified Store event logs after they've been synced to the configured storage adapter. These logs may not reflect exactly the events that are on chain when e.g. hydrating from an indexer, but they will still allow the client to "catch up" to the on-chain state of your tables.
Patch Changes
-
#1484
6573e38e
Thanks @alvrs! - Renamed all occurrences oftable
where it is used as "table ID" totableId
.
This is only a breaking change for consumers who manually decodeStore
events, but not for consumers who use the MUD libraries.event StoreSetRecord( - bytes32 table, + bytes32 tableId, bytes32[] key, bytes data ); event StoreSetField( - bytes32 table, + bytes32 tableId, bytes32[] key, uint8 fieldIndex, bytes data ); event StoreDeleteRecord( - bytes32 table, + bytes32 tableId, bytes32[] key ); event StoreEphemeralRecord( - bytes32 table, + bytes32 tableId, bytes32[] key, bytes data );
-
#1492
6e66c5b7
Thanks @alvrs! - Renamed all occurrences ofkey
where it is used as "key tuple" tokeyTuple
.
This is only a breaking change for consumers who manually decodeStore
events, but not for consumers who use the MUD libraries.event StoreSetRecord( bytes32 tableId, - bytes32[] key, + bytes32[] keyTuple, bytes data ); event StoreSetField( bytes32 tableId, - bytes32[] key, + bytes32[] keyTuple, uint8 fieldIndex, bytes data ); event StoreDeleteRecord( bytes32 tableId, - bytes32[] key, + bytes32[] keyTuple, ); event StoreEphemeralRecord( bytes32 tableId, - bytes32[] key, + bytes32[] keyTuple, bytes data );
-
#1488
7e6e5157
Thanks @holic! - Catch errors when parsing logs to tables and storage operations, log and skip -
#1586
22ee4470
Thanks @alvrs! - AllStore
andWorld
tables now use the appropriate user-types forResourceId
,FieldLayout
andSchema
to avoid manualwrap
/unwrap
. -
#1558
bfcb293d
Thanks @alvrs! - What used to be known asephemeral
table is now calledoffchain
table.
The previousephemeral
tables only supported anemitEphemeral
method, which emitted aStoreSetEphemeralRecord
event.Now
offchain
tables support all regular table methods, except partial operations on dynamic fields (push
,pop
,update
).
Unlike regular tables they don't store data on-chain but emit the same events as regular tables (StoreSetRecord
,StoreSpliceStaticData
,StoreDeleteRecord
), so their data can be indexed by offchain indexers/clients.- EphemeralTable.emitEphemeral(value); + OffchainTable.set(value);
-
#1601
1890f1a0
Thanks @alvrs! - Movedstore
tables to the"store"
namespace (previously "mudstore") andworld
tables to the"world"
namespace (previously root namespace). -
#1577
af639a26
Thanks @alvrs! -Store
events have been renamed for consistency and readability.
If you're parsingStore
events manually, you need to update your ABI.
If you're using the MUD sync stack, the new events are already integrated and no further changes are necessary.- event StoreSetRecord( + event Store_SetRecord( ResourceId indexed tableId, bytes32[] keyTuple, bytes staticData, bytes32 encodedLengths, bytes dynamicData ); - event StoreSpliceStaticData( + event Store_SpliceStaticData( ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, uint40 deleteCount, bytes data ); - event StoreSpliceDynamicData( + event Store_SpliceDynamicData( ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, uint40 deleteCount, bytes data, bytes32 encodedLengths ); - event StoreDeleteRecord( + event Store_DeleteRecord( ResourceId indexed tableId, bytes32[] keyTuple );
-
#1581
cea754dd
Thanks @alvrs! - - The externalsetRecord
anddeleteRecord
methods ofIStore
no longer accept aFieldLayout
as input, but load it from storage instead.
This is to prevent invalidFieldLayout
values being passed, which could cause the onchain state to diverge from the indexer state.
However, the internalStoreCore
library still exposes asetRecord
anddeleteRecord
method that allows aFieldLayout
to be passed.
This is becauseStoreCore
can only be used internally, so theFieldLayout
value can be trusted and we can save the gas for accessing storage.interface IStore { function setRecord( ResourceId tableId, bytes32[] calldata keyTuple, bytes calldata staticData, PackedCounter encodedLengths, bytes calldata dynamicData, - FieldLayout fieldLayout ) external; function deleteRecord( ResourceId tableId, bytes32[] memory keyTuple, - FieldLayout fieldLayout ) external; }
-
The
spliceStaticData
method andStore_SpliceStaticData
event ofIStore
andStoreCore
no longer includedeleteCount
in their signature.
This is because when splicing static data, the data afterstart
is always overwritten withdata
instead of being shifted, sodeleteCount
is always the length of the data to be written.event Store_SpliceStaticData( ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, - uint40 deleteCount, bytes data ); interface IStore { function spliceStaticData( ResourceId tableId, bytes32[] calldata keyTuple, uint48 start, - uint40 deleteCount, bytes calldata data ) external; }
-
The
updateInField
method has been removed fromIStore
, as it's almost identical to the more generalspliceDynamicData
.
If you're manually callingupdateInField
, here is how to upgrade tospliceDynamicData
:- store.updateInField(tableId, keyTuple, fieldIndex, startByteIndex, dataToSet, fieldLayout); + uint8 dynamicFieldIndex = fieldIndex - fieldLayout.numStaticFields(); + store.spliceDynamicData(tableId, keyTuple, dynamicFieldIndex, uint40(startByteIndex), uint40(dataToSet.length), dataToSet);
-
All other methods that are only valid for dynamic fields (
pushToField
,popFromField
,getFieldSlice
)
have been renamed to make this more explicit (pushToDynamicField
,popFromDynamicField
,getDynamicFieldSlice
).Their
fieldIndex
parameter has been replaced by adynamicFieldIndex
parameter, which is the index relative to the first dynamic field (i.e.dynamicFieldIndex
=fieldIndex
-numStaticFields
).
TheFieldLayout
parameter has been removed, as it was only used to calculate thedynamicFieldIndex
in the method.interface IStore { - function pushToField( + function pushToDynamicField( ResourceId tableId, bytes32[] calldata keyTuple, - uint8 fieldIndex, + uint8 dynamicFieldIndex, bytes calldata dataToPush, - FieldLayout fieldLayout ) external; - function popFromField( + function popFromDynamicField( ResourceId tableId, bytes32[] calldata keyTuple, - uint8 fieldIndex, + uint8 dynamicFieldIndex, uint256 byteLengthToPop, - FieldLayout fieldLayout ) external; - function getFieldSlice( + function getDynamicFieldSlice( ResourceId tableId, bytes32[] memory keyTuple, - uint8 fieldIndex, + uint8 dynamicFieldIndex, - FieldLayout fieldLayout, uint256 start, uint256 end ) external view returns (bytes memory data); }
-
IStore
has a newgetDynamicFieldLength
length method, which returns the byte length of the given dynamic field and doesn't require theFieldLayout
.IStore { + function getDynamicFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex + ) external view returns (uint256); }
-
IStore
now has additional overloads forgetRecord
,getField
,getFieldLength
andsetField
that don't require aFieldLength
to be passed, but instead load it from storage. -
IStore
now exposessetStaticField
andsetDynamicField
to save gas by avoiding the dynamic inference of whether the field is static or dynamic. -
The
getDynamicFieldSlice
method no longer accepts reading outside the bounds of the dynamic field.
This is to avoid returning invalid data, as the data of a dynamic field is not deleted when the record is deleted, but only its length is set to zero.
-
-
Updated dependencies [
77dce993
,748f4588
,aea67c58
,07dd6f32
,c07fa021
,90e4161b
,65c9546c
,331dbfdc
,f9f9609e
,331dbfdc
,759514d8
,d5094a24
,0b8ce3f2
,de151fec
,ae340b2b
,e5d208e4
,211be2a1
,0f3e2e02
,1f80a0b5
,d0878928
,4c7fd3eb
,a0341daf
,83583a50
,5e723b90
,6573e38e
,44a5432a
,6e66c5b7
,65c9546c
,f8a01a04
,44a5432a
,672d05ca
,f1cd43bf
,31ffc9d5
,5e723b90
,63831a26
,331dbfdc
,92de5998
,5741d53d
,22ee4470
,be313068
,ac508bf1
,9ff4dd95
,bfcb293d
,1890f1a0
,9b43029c
,55ab88a6
,af639a26
,5e723b90
,99ab9cd6
,c049c23f
,80dd6992
,24a6cd53
,708b49c5
,22ba7b67
,c049c23f
,251170e1
,c4f49240
,cea754dd
,95c59b20
]:- @latticexyz/[email protected]
- @latticexyz/[email protected]
- @latticexyz/[email protected]
- @latticexyz/[email protected]
- @latticexyz/[email protected]
- @latticexyz/[email protected]
- @latticexyz/[email protected]