-
Notifications
You must be signed in to change notification settings - Fork 188
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
Proposal: make Store events independent of schema #1222
Comments
yeah I tried this when making the specialized methods, a naive splice implementation would cost more gas
we could change StoreCore methods to accommodate libraries doing all the work, at which point there won't be much left of StoreCore (it still has to handle dynamic lengths?) and it would be closer to directly mirroring Storage's
if we go with schema, we could instead go further and make everything a field. So remove the notion of record, and (both ideas are dubious: |
So you're saying there are other libraries around store that handle how the low level store methods are used? I guess that would mean the
Interesting idea, let's spin it further to see what it would look like. We could have events like event StoreSetField(bytes32 table, bytes32[] key, uint8 schemaIndex, bytes data) // Exactly how it is currently
event StoreSpliceField(bytes32 table, bytes32[] key, uint8 schemaIndex, uint40 start, uint40 deleteCount, bytes data) // partially update a field Advantages
Disadvantages
|
@holic just had a good point: we only need the dynamic data length when setting dynamic fields (if it's a static field we can compute it from the schema), and we already read and write the dynamic data length for |
I meant the autogenerated table libraries, separating StoreCore into several libs isn't really related to this |
After more consideration it seems like a worthwhile tradeoff to replace |
Current situation
Store events:
StoreSetRecord
is independent of schemaStoreSetField
only contains data of a single field and needs context of the schema to know how to update the recordStoreDeleteRecord
is independent of schemaStoreEphemeralRecord
is independent of schema. I will ignore this event for the rest of this proposal because it is handled identical toStoreSetRecord
.StoreSetPartialField
). This is relevant for updating dynamic fields (eg pushing an element to an array). Currently we need to load the entire field from storage on chain, to update it and then to be able to emit it as part of theStoreSetField
event. Instead we should have an event that accepts partial field data and sufficient context for indexers / clients to be able to update the dynamic field.StoreSetRecord
andStoreDeleteRecord
are independent of the schema, they can be processed in parallel: a simple event indexer can load these events from all blocks in a block range in parallel and insert them into a database including a reference to the block in which they occurred. In a second step this list of events can be filtered to only include the last event corresponding to each record.StoreSetField
we can still sync all events in parallel, but the filter step becomes much more complex: we only care about theStoreSetField
events after the lastStoreSetRecord
event for a given record, but to apply these events to compute the final record value we need context on the record’s schema (because the event includes aschemaIndex
to indicate which field was updated). The table’s schema is stored in the schema table, and is emitted as aStoreSetRecord
event before the first event of the new table. In other words, processing theStoreSetField
event depends on other events earlier in the event stream.Proposal
Change the
StoreSetField
event to a more pureStoreSpliceRecord
eventStoreSetField
event to include sufficient context to update the record without context of the schema, processingStoreSetField
events becomes much simpler.tableId
andkey
behave as before: they uniquely identify a recordstart
is the byte index at which to change the recordstart >= record.length
no data will be deleted, but the data passed as last argument will be appended at the end of the recorddeleteCount
is the number of bytes to delete starting fromstart
data
is the data to be inserted afterstart
StoreSpiceRecord
for all operations and removeStoreSetRecord
(and potentially evenStoreDeleteRecord
). However I think it’s still useful to have an explicit notion of setting a full record and deleting a record, because it makes it easier to reduce a list of events into the current record value, because all events before aStoreSetRecord
orStoreDeleteRecord
for a given record can be ignored.StoreSpliceRecord
could also be used for updating a partial field instead of an explicitStoreSetPartialField
StoreSetField
event explicitly indicated which field to update, whileStoreSpliceRecord
would require those clients to first encode the current record, then update the blob of bytes and finally decode the record again.StoreSpliceRecord
has no guarantee to only touch a single field, so it would be way more complex to compute which field the byte index corresponds to to only update this field. This also means it’s more complex to know which field was updated (you’d have to compare the decoded previous record with the decoded record after the update), but our current libraries only indicate which record was updated as well.Implementation
StoreSetField
inStoreCore
'ssetField
,pushToField
,popFromField
andupdateInField
methods.setField
start
fromschemaIndex
by computing the sum of all field lengths before the schema index (_getStaticDataOffset
for static fields, full static data length + 32B packed counter + sum of all dynamic fields up to the field to update for dynamic fields)deleteCount
(static byte length for static fields, dynamic length for dynamic fields)data
as it ispushToField
start
(full static length + 32B packed counter + lengths of all dynamic fields including the field to push to)deleteCount
to 0data
as it ispopFromField
start
(full static length + 32B packed counter + lengths of all dynamic fields including the field to push to -byteLengthToPop
)deleteCount
tobyteLengthToPop
new bytes(0)
asdata
updateInField
start
(full static length + 32B packed counter + length of all dynamic fields up to the field to push to +startByteIndex
deleteCount
todataToSet.length
dataToSet
asdata
sload
to get the current length of all dynamic fields to computestart
Additional thoughts
spliceRecord
instead ofsetField
,pushToField
,popFromField
,updateInField
?StoreCore
and inside codegen libraries / consumerThe text was updated successfully, but these errors were encountered: