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(store): add splice events #1354

Merged
merged 83 commits into from Sep 16, 2023
Merged

feat(store): add splice events #1354

merged 83 commits into from Sep 16, 2023

Conversation

dk1a
Copy link
Member

@dk1a dk1a commented Aug 22, 2023

fixes #1222
fixes #1296

TODO:

  • add tests for recs sync
  • add more tests for splice to make sure sync does the right thing
    • splicing an empty record
    • splicing on a unset field
    • decoding default values for unset fields
  • finalize naming/position of packed counter args on splice event
  • should we return bytes16 from Schema.staticDataLength()? since that's what it's actually stored as?
  • explain start/deleteCount types
  • figure out if its gas efficient enough to remove total length from encoded lengths moved to explore removing total length from PackedCounter #1420
  • revisit naming (StoreSpliceStaticRecord -> StoreSpliceStaticData)

@changeset-bot
Copy link

changeset-bot bot commented Aug 22, 2023

🦋 Changeset detected

Latest commit: 9a2382c

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

This PR includes changesets to release 28 packages
Name Type
@latticexyz/store Major
@latticexyz/world Major
@latticexyz/common Major
@latticexyz/protocol-parser Major
@latticexyz/dev-tools Major
@latticexyz/store-sync Major
create-mud Major
@latticexyz/cli Major
@latticexyz/react Major
@latticexyz/store-indexer Major
@latticexyz/block-logs-stream Major
@latticexyz/config Major
@latticexyz/abi-ts Major
@latticexyz/ecs-browser Major
@latticexyz/gas-report Major
@latticexyz/network Major
@latticexyz/noise Major
@latticexyz/phaserx 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/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

@alvrs alvrs changed the title WIP StoreSpliceRecord feat(store): add StoreSpliceField event Aug 24, 2023
@dk1a
Copy link
Member Author

dk1a commented Aug 24, 2023

The on-chain part is ready
Curious if you've already thought about the sync @alvrs @holic
The way I'm currently doing recs sync is bad, I guess we'd need to either do a middle bytes layer, or a splice parser that figures out which fields to update (with partial updates being the tricky part)

@alvrs alvrs changed the title feat(store): add StoreSpliceField event feat(store): add StoreSpliceRecord event Aug 24, 2023
Comment on lines 162 to 164
data: log.args.data,
start: log.args.start,
deleteCount: log.args.deleteCount,
Copy link
Member

Choose a reason for hiding this comment

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

Is there a way we could perform the steps to combine the new bytes with an existing record in here? Or would that prevent some optimizations we can do downstream (like encode+splice+decode in a single db tx)?

@@ -693,7 +693,7 @@
"file": "test/StoreCoreGas.t.sol",
"test": "testSetAndGetField",
"name": "set static field (1 slot)",
"gasUsed": 33280
"gasUsed": 33581
Copy link
Member

Choose a reason for hiding this comment

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

+300 in gas; some increase is expected, is there anything we can do to further optimize this or is this as good as it gets?

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 didn't intentionally spend time optimizing gas here, probably can do better when I get to StoreCore

Comment on lines 559 to 570
// Prepare data for the splice event
uint256 start;
unchecked {
// (safe because it's a few uint40 values, which can't overflow uint48)
start = valueSchema.staticDataLength() + 32;
for (uint8 i; i < dynamicSchemaIndex; i++) {
start += encodedLengths.atIndex(i);
}
}
uint256 deleteCount = oldFieldLength;
// Emit event to notify indexers
emit StoreCore.StoreSpliceRecord(tableId, key, uint48(start), uint40(deleteCount), data);
Copy link
Member

Choose a reason for hiding this comment

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

Is it worth generalizing this in an internal util function, since very similar logic is used for _setDynamicField, _pushToDynamicField, _popFromDynamicField and _setDynamicFieldItem? I feel like might declutter the code a bit, make it easier to audit and easier to write tests for this logic in isolation

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've been thinking about this for a while now. I think the only efficient way to declutter is generalize it in a renderer function, and render StoreCore. Using solidity functions means more gas because the optimizer won't inline any of it and we'll need to return many vars

Copy link
Member Author

Choose a reason for hiding this comment

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

Or we could not worry about gas I guess, it's probably less than 1000 (haven't tested specifics). Though a bunch of return vars may still be ugly compared to a renderer with conditionals in the relevant places

Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately I think a renderer would make auditing harder (because auditors have less experience with codegen). I'd be curious about the gas implications of moving it to a helper function, if it's a significant increase i'm also fine with keeping it inline

Copy link
Member Author

Choose a reason for hiding this comment

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

@alvrs do you want declutter in this PR? it feels like it'd be better in a separate one for easier reverts and gas comparisons

Copy link
Member

Choose a reason for hiding this comment

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

can try to refactor in a separate PR

Comment on lines 17 to 19
// We use a specific, invalid packed counter (total length != sum of lengths) to represent "unchanged" for the purpose of events and off-chain indexing
bytes32 constant UNCHANGED_PACKED_COUNTER = bytes32(uint256(1));

Copy link
Member

Choose a reason for hiding this comment

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

do we still need this? doesn't seem like it's used

Copy link
Member

@holic holic Sep 15, 2023

Choose a reason for hiding this comment

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

we're not using it yet so feel free to trash (which I see you've already done), can add later

alvrs
alvrs previously approved these changes Sep 15, 2023
Copy link
Member

@alvrs alvrs left a comment

Choose a reason for hiding this comment

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

lgtm, amazing work @dk1a @holic. Let's get this over the finish line. Only thing missing is a changeset.

@holic
Copy link
Member

holic commented Sep 16, 2023

added follow up issue for splice tests: #1515

@holic holic merged commit 331dbfd into main Sep 16, 2023
10 checks passed
@holic holic deleted the dk1a/storespliceevent branch September 16, 2023 12:23
alvrs added a commit to Boffee/mud that referenced this pull request Sep 16, 2023
Co-authored-by: Kevin Ingersoll <kingersoll@gmail.com>
Co-authored-by: alvrs <alvarius@lattice.xyz>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants