From 2024ef10898ef16fe5289ce7417c4295d9acdbfb Mon Sep 17 00:00:00 2001 From: Dhvani Patel Date: Tue, 7 Nov 2023 14:12:03 -0500 Subject: [PATCH 1/3] add hook --- packages/recs/src/Component.ts | 8 +- packages/store-sync/src/recs/recsStorage.ts | 87 ++++++++++++++++----- packages/store-sync/src/recs/syncToRecs.ts | 18 +++-- 3 files changed, 86 insertions(+), 27 deletions(-) diff --git a/packages/recs/src/Component.ts b/packages/recs/src/Component.ts index dc4be8750c..662e26f960 100644 --- a/packages/recs/src/Component.ts +++ b/packages/recs/src/Component.ts @@ -110,6 +110,8 @@ export function setComponent( } } component.update$.next({ entity, value: [value, prevValue], component }); + const updateValue = { entity, value: [value, prevValue], component }; + return updateValue; } /** @@ -139,9 +141,9 @@ export function updateComponent( if (initialValue === undefined) { throw new Error(`Can't update component ${getComponentName(component)} without a current value or initial value`); } - setComponent(component, entity, { ...initialValue, ...value }); + return setComponent(component, entity, { ...initialValue, ...value }); } else { - setComponent(component, entity, { ...currentValue, ...value }); + return setComponent(component, entity, { ...currentValue, ...value }); } } @@ -161,6 +163,8 @@ export function removeComponent>; -export function recsStorage({ - components, -}: { - components: ReturnType & - Record>; - config?: TConfig; -}): BlockLogsToStorageOptions { +export type RecsUpdatesHook = ( + blockNumber: BlockLogs["blockNumber"], + componentEntityUpdates: ComponentEntityUpdates +) => Promise; + +export function recsStorage( + { + components, + address, + }: { + components: ReturnType & + Record>; + config?: TConfig; + address: `0x${string}` | undefined; + }, + recsAllUpdatesHook?: RecsUpdatesHook +): BlockLogsToStorageOptions { // TODO: do we need to store block number? const componentsByTableId = Object.fromEntries( @@ -44,7 +59,9 @@ export function recsStorage({ .map((table) => getComponentValue(components.RegisteredTables, getTableEntity(table))?.table) .filter(isDefined); }, - async storeOperations({ operations }) { + async storeOperations({ blockNumber, operations }) { + const componentEntityUpdates: ComponentEntityUpdates = new Map>(); + console.log("processing updates for world", blockNumber, address); for (const operation of operations) { const table = getComponentValue( components.RegisteredTables, @@ -68,14 +85,15 @@ export function recsStorage({ const entity = encodeEntity(table.keySchema, operation.key); + let newUpdate = undefined; if (operation.type === "SetRecord") { debug("setting component", tableId, entity, operation.value); - setComponent(component, entity, operation.value as ComponentValue); + newUpdate = setComponent(component, entity, operation.value as ComponentValue); } else if (operation.type === "SetField") { debug("updating component", tableId, entity, { [operation.fieldName]: operation.fieldValue, }); - updateComponent( + newUpdate = updateComponent( component, entity, { [operation.fieldName]: operation.fieldValue } as ComponentValue, @@ -83,9 +101,42 @@ export function recsStorage({ ); } else if (operation.type === "DeleteRecord") { debug("deleting component", tableId, entity); - removeComponent(component, entity); + newUpdate = removeComponent(component, entity); + } + + if (newUpdate) { + // console.log("component updates"); + if (componentEntityUpdates.has(newUpdate.component.id)) { + // JS reference so don't need to set again + if (componentEntityUpdates.get(newUpdate.component.id)?.has(newUpdate.entity)) { + componentEntityUpdates.get(newUpdate.component.id)?.get(newUpdate.entity)?.push(newUpdate); + } else { + componentEntityUpdates.get(newUpdate.component.id)?.set(newUpdate.entity, [newUpdate]); + } + } else { + const entityUpdates = new Map(); + entityUpdates.set(newUpdate.entity, [newUpdate]); + componentEntityUpdates.set(newUpdate.component.id, entityUpdates); + } } } + + // console.log("end of tx"); + // console.log("blockNumber", blockNumber); + // componentEntityUpdates.forEach((entityUpdates, component) => { + // console.log('component', component); + // entityUpdates.forEach((updates, entity) => { + // console.log('entity', entity); + // updates.forEach((update) => { + // console.log(update.value); + // }); + // }); + // console.log("done"); + // }); + if (recsAllUpdatesHook !== undefined) { + console.log("calling hook for world", blockNumber, address); + await recsAllUpdatesHook(blockNumber, componentEntityUpdates); + } }, } as BlockLogsToStorageOptions; } diff --git a/packages/store-sync/src/recs/syncToRecs.ts b/packages/store-sync/src/recs/syncToRecs.ts index d2c2b006e8..b84306ece0 100644 --- a/packages/store-sync/src/recs/syncToRecs.ts +++ b/packages/store-sync/src/recs/syncToRecs.ts @@ -1,20 +1,21 @@ -import { StoreConfig } from "@latticexyz/store"; import { World as RecsWorld, getComponentValue, setComponent } from "@latticexyz/recs"; +import { StoreConfig } from "@latticexyz/store"; +import storeConfig from "@latticexyz/store/mud.config.js"; +import worldConfig from "@latticexyz/world/mud.config.js"; +import { SyncStep } from "../SyncStep"; import { SyncOptions, SyncResult } from "../common"; -import { recsStorage } from "./recsStorage"; -import { defineInternalComponents } from "./defineInternalComponents"; import { createStoreSync } from "../createStoreSync"; import { ConfigToRecsComponents } from "./common"; -import storeConfig from "@latticexyz/store/mud.config.js"; -import worldConfig from "@latticexyz/world/mud.config.js"; import { configToRecsComponents } from "./configToRecsComponents"; +import { defineInternalComponents } from "./defineInternalComponents"; +import { RecsUpdatesHook, recsStorage } from "./recsStorage"; import { singletonEntity } from "./singletonEntity"; -import { SyncStep } from "../SyncStep"; type SyncToRecsOptions = SyncOptions & { world: RecsWorld; config: TConfig; startSync?: boolean; + recsAllUpdatesHook?: RecsUpdatesHook; }; type SyncToRecsResult = SyncResult & { @@ -34,6 +35,7 @@ export async function syncToRecs({ maxBlockRange, initialState, indexerUrl, + recsAllUpdatesHook, startSync = true, }: SyncToRecsOptions): Promise> { const components = { @@ -45,8 +47,10 @@ export async function syncToRecs({ world.registerEntity({ id: singletonEntity }); + console.log("syncWithRecs", startBlock, address); + const storeSync = await createStoreSync({ - storageAdapter: recsStorage({ components, config }), + storageAdapter: recsStorage({ components, config, address }, recsAllUpdatesHook), config, address, publicClient, From 711be5273e025a65062231fcb843481f2d77e7e3 Mon Sep 17 00:00:00 2001 From: Dhvani Patel Date: Tue, 7 Nov 2023 20:45:37 -0500 Subject: [PATCH 2/3] remove logs --- packages/store-sync/src/recs/recsStorage.ts | 16 ---------------- packages/store-sync/src/recs/syncToRecs.ts | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/packages/store-sync/src/recs/recsStorage.ts b/packages/store-sync/src/recs/recsStorage.ts index d7a3fcd074..9959c517d2 100644 --- a/packages/store-sync/src/recs/recsStorage.ts +++ b/packages/store-sync/src/recs/recsStorage.ts @@ -61,7 +61,6 @@ export function recsStorage( }, async storeOperations({ blockNumber, operations }) { const componentEntityUpdates: ComponentEntityUpdates = new Map>(); - console.log("processing updates for world", blockNumber, address); for (const operation of operations) { const table = getComponentValue( components.RegisteredTables, @@ -105,9 +104,7 @@ export function recsStorage( } if (newUpdate) { - // console.log("component updates"); if (componentEntityUpdates.has(newUpdate.component.id)) { - // JS reference so don't need to set again if (componentEntityUpdates.get(newUpdate.component.id)?.has(newUpdate.entity)) { componentEntityUpdates.get(newUpdate.component.id)?.get(newUpdate.entity)?.push(newUpdate); } else { @@ -121,20 +118,7 @@ export function recsStorage( } } - // console.log("end of tx"); - // console.log("blockNumber", blockNumber); - // componentEntityUpdates.forEach((entityUpdates, component) => { - // console.log('component', component); - // entityUpdates.forEach((updates, entity) => { - // console.log('entity', entity); - // updates.forEach((update) => { - // console.log(update.value); - // }); - // }); - // console.log("done"); - // }); if (recsAllUpdatesHook !== undefined) { - console.log("calling hook for world", blockNumber, address); await recsAllUpdatesHook(blockNumber, componentEntityUpdates); } }, diff --git a/packages/store-sync/src/recs/syncToRecs.ts b/packages/store-sync/src/recs/syncToRecs.ts index b84306ece0..1dd176e1f9 100644 --- a/packages/store-sync/src/recs/syncToRecs.ts +++ b/packages/store-sync/src/recs/syncToRecs.ts @@ -47,7 +47,7 @@ export async function syncToRecs({ world.registerEntity({ id: singletonEntity }); - console.log("syncWithRecs", startBlock, address); + // console.log("syncWithRecs", startBlock, address); const storeSync = await createStoreSync({ storageAdapter: recsStorage({ components, config, address }, recsAllUpdatesHook), From 945f3d70822abd398745cd98d511d5dddea5e6da Mon Sep 17 00:00:00 2001 From: Dhvani Patel Date: Tue, 7 Nov 2023 20:46:34 -0500 Subject: [PATCH 3/3] remove address param --- packages/store-sync/src/recs/recsStorage.ts | 2 -- packages/store-sync/src/recs/syncToRecs.ts | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/store-sync/src/recs/recsStorage.ts b/packages/store-sync/src/recs/recsStorage.ts index 9959c517d2..363f601f17 100644 --- a/packages/store-sync/src/recs/recsStorage.ts +++ b/packages/store-sync/src/recs/recsStorage.ts @@ -31,12 +31,10 @@ export type RecsUpdatesHook = ( export function recsStorage( { components, - address, }: { components: ReturnType & Record>; config?: TConfig; - address: `0x${string}` | undefined; }, recsAllUpdatesHook?: RecsUpdatesHook ): BlockLogsToStorageOptions { diff --git a/packages/store-sync/src/recs/syncToRecs.ts b/packages/store-sync/src/recs/syncToRecs.ts index 1dd176e1f9..e20a8d60cd 100644 --- a/packages/store-sync/src/recs/syncToRecs.ts +++ b/packages/store-sync/src/recs/syncToRecs.ts @@ -47,10 +47,8 @@ export async function syncToRecs({ world.registerEntity({ id: singletonEntity }); - // console.log("syncWithRecs", startBlock, address); - const storeSync = await createStoreSync({ - storageAdapter: recsStorage({ components, config, address }, recsAllUpdatesHook), + storageAdapter: recsStorage({ components, config }, recsAllUpdatesHook), config, address, publicClient,