Skip to content

Commit

Permalink
feat(torii-core): store update member (#2182)
Browse files Browse the repository at this point in the history
* feat(torii-core): store update member

* feat; add set_model_member for updating specific member

* chore: format

* chore: update log to include member nname

* fmt

* refactor: clean code & add is event message

* fmt

* chore

* feat: emit the store member update from the world

* fix: ensure event messages are emitted with the correct selector

* fix: cairo fmt

* fix: fix test typo

* wip:

* fix: simple types model memebr update

* chore; pass memmber type to func

* chore: clean code

* fmt

* wip

* fix: upsert to avoid constraint CHECK failing

* fmt

* fix: figure out way to fix upsert issue to reuse func

* refactor: refactor recursive set to handle store update member

* fix: fix world typo and merge

* fix: struct from ty as mutable

* fix: compilable torii

* feat: wrap up store update member

* fmt

* fix fmt

* fmt

* cairo fmt

* fix: update example to set array with new model API

* fix: handle arrays

* fix: correctly handle arrays

* chore

* fix: test

---------

Co-authored-by: glihm <dev@glihm.net>
  • Loading branch information
Larkooo and glihm authored Aug 1, 2024
1 parent 1b75ac9 commit f490222
Show file tree
Hide file tree
Showing 26 changed files with 564 additions and 82 deletions.
41 changes: 36 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions bin/torii/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use torii_core::processors::register_model::RegisterModelProcessor;
use torii_core::processors::store_del_record::StoreDelRecordProcessor;
use torii_core::processors::store_set_record::StoreSetRecordProcessor;
use torii_core::processors::store_transaction::StoreTransactionProcessor;
use torii_core::processors::store_update_member::StoreUpdateMemberProcessor;
use torii_core::processors::store_update_record::StoreUpdateRecordProcessor;
use torii_core::simple_broker::SimpleBroker;
use torii_core::sql::Sql;
Expand Down Expand Up @@ -172,6 +173,7 @@ async fn main() -> anyhow::Result<()> {
Box::new(StoreDelRecordProcessor),
Box::new(EventMessageProcessor),
Box::new(StoreUpdateRecordProcessor),
Box::new(StoreUpdateMemberProcessor),
],
transaction: vec![Box::new(StoreTransactionProcessor)],
..Processors::default()
Expand Down
23 changes: 20 additions & 3 deletions crates/dojo-core/src/world/world_contract.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ pub mod world {
ModelRegistered: ModelRegistered,
StoreSetRecord: StoreSetRecord,
StoreUpdateRecord: StoreUpdateRecord,
StoreUpdateMember: StoreUpdateMember,
StoreDelRecord: StoreDelRecord,
WriterUpdated: WriterUpdated,
OwnerUpdated: OwnerUpdated,
Expand Down Expand Up @@ -219,6 +220,14 @@ pub mod world {
pub values: Span<felt252>,
}

#[derive(Drop, starknet::Event)]
pub struct StoreUpdateMember {
pub table: felt252,
pub entity_id: felt252,
pub member_selector: felt252,
pub values: Span<felt252>,
}

#[derive(Drop, starknet::Event)]
pub struct StoreDelRecord {
pub table: felt252,
Expand Down Expand Up @@ -821,10 +830,18 @@ pub mod world {
);
},
ModelIndex::MemberId((
entity_id, member_id
entity_id, member_selector
)) => {
self.write_model_member(model_selector, entity_id, member_id, values, layout);
// TODO: here we need a new event update and see how Torii can process that.
self
.write_model_member(
model_selector, entity_id, member_selector, values, layout
);
EventEmitter::emit(
ref self,
StoreUpdateMember {
table: model_selector, entity_id, member_selector, values
}
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,33 @@
}
]
},
{
"type": "event",
"name": "dojo::world::world_contract::world::StoreUpdateMember",
"kind": "struct",
"members": [
{
"name": "table",
"type": "core::felt252",
"kind": "data"
},
{
"name": "entity_id",
"type": "core::felt252",
"kind": "data"
},
{
"name": "member_selector",
"type": "core::felt252",
"kind": "data"
},
{
"name": "values",
"type": "core::array::Span::<core::felt252>",
"kind": "data"
}
]
},
{
"type": "event",
"name": "dojo::world::world_contract::world::StoreDelRecord",
Expand Down Expand Up @@ -1156,6 +1183,11 @@
"type": "dojo::world::world_contract::world::StoreUpdateRecord",
"kind": "nested"
},
{
"name": "StoreUpdateMember",
"type": "dojo::world::world_contract::world::StoreUpdateMember",
"kind": "nested"
},
{
"name": "StoreDelRecord",
"type": "dojo::world::world_contract::world::StoreDelRecord",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
kind = "Class"
class_hash = "0x4c90da98d2bad157dec1d7b9b9c8c5861828a7ec1b323425d84fa6c3071303f"
original_class_hash = "0x4c90da98d2bad157dec1d7b9b9c8c5861828a7ec1b323425d84fa6c3071303f"
class_hash = "0x2178527e9556d1aa21d3c2961d28f9114fcfed81b4c3674ed591c50ce46cc9d"
original_class_hash = "0x2178527e9556d1aa21d3c2961d28f9114fcfed81b4c3674ed591c50ce46cc9d"
abi = "manifests/dev/base/abis/dojo-world.json"
tag = "dojo-world"
manifest_name = "dojo-world"
32 changes: 32 additions & 0 deletions crates/dojo-world/src/contracts/abi/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,33 @@ abigen!(
}
]
},
{
"type": "event",
"name": "dojo::world::world_contract::world::StoreUpdateMember",
"kind": "struct",
"members": [
{
"name": "table",
"type": "core::felt252",
"kind": "data"
},
{
"name": "entity_id",
"type": "core::felt252",
"kind": "data"
},
{
"name": "member_selector",
"type": "core::felt252",
"kind": "data"
},
{
"name": "values",
"type": "core::array::Span::<core::felt252>",
"kind": "data"
}
]
},
{
"type": "event",
"name": "dojo::world::world_contract::world::StoreDelRecord",
Expand Down Expand Up @@ -1162,6 +1189,11 @@ abigen!(
"type": "dojo::world::world_contract::world::StoreUpdateRecord",
"kind": "nested"
},
{
"name": "StoreUpdateMember",
"type": "dojo::world::world_contract::world::StoreUpdateMember",
"kind": "nested"
},
{
"name": "StoreDelRecord",
"type": "dojo::world::world_contract::world::StoreDelRecord",
Expand Down
2 changes: 1 addition & 1 deletion crates/sozo/ops/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ mod tests {
let result = extract_events(&manifest, &project_dir, &target_dir).unwrap();

// we are just collecting all events from manifest file so just verifying count should work
assert_eq!(result.len(), 17);
assert_eq!(result.len(), 18);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion crates/sozo/ops/src/tests/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async fn test_model_ops() {
)
.await
.unwrap(),
Felt::from_hex("0x2b14bbb22e6a21cc949e06a187436c96aeab0e0290b3a8d91fb357ed2e6d973")
Felt::from_hex("0x4eddd8563a17c7d256b35e3cb0decdfcdfe122dd72593ebc572cfc535941ac2")
.unwrap()
);

Expand Down
1 change: 1 addition & 0 deletions crates/torii/core/src/processors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod register_model;
pub mod store_del_record;
pub mod store_set_record;
pub mod store_transaction;
pub mod store_update_member;
pub mod store_update_record;

const MODEL_INDEX: usize = 0;
Expand Down
108 changes: 108 additions & 0 deletions crates/torii/core/src/processors/store_update_member.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use anyhow::{Context, Error, Result};
use async_trait::async_trait;
use dojo_world::contracts::model::ModelReader;
use dojo_world::contracts::naming;
use dojo_world::contracts::world::WorldContractReader;
use num_traits::ToPrimitive;
use starknet::core::types::{Event, TransactionReceiptWithBlockInfo};
use starknet::core::utils::get_selector_from_name;
use starknet::providers::Provider;
use tracing::{info, warn};

use super::EventProcessor;
use crate::processors::{ENTITY_ID_INDEX, MODEL_INDEX};
use crate::sql::Sql;

pub(crate) const LOG_TARGET: &str = "torii_core::processors::store_update_member";

const MEMBER_INDEX: usize = 2;

#[derive(Default, Debug)]
pub struct StoreUpdateMemberProcessor;

#[async_trait]
impl<P> EventProcessor<P> for StoreUpdateMemberProcessor
where
P: Provider + Send + Sync + std::fmt::Debug,
{
fn event_key(&self) -> String {
"StoreUpdateMember".to_string()
}

fn validate(&self, event: &Event) -> bool {
if event.keys.len() > 1 {
info!(
target: LOG_TARGET,
event_key = %<StoreUpdateMemberProcessor as EventProcessor<P>>::event_key(self),
invalid_keys = %<StoreUpdateMemberProcessor as EventProcessor<P>>::event_keys_as_string(self, event),
"Invalid event keys."
);
return false;
}
true
}

async fn process(
&self,
_world: &WorldContractReader<P>,
db: &mut Sql,
_block_number: u64,
block_timestamp: u64,
_transaction_receipt: &TransactionReceiptWithBlockInfo,
event_id: &str,
event: &Event,
) -> Result<(), Error> {
let selector = event.data[MODEL_INDEX];
let entity_id = event.data[ENTITY_ID_INDEX];
let member_selector = event.data[MEMBER_INDEX];

let model = db.model(selector).await?;
let schema = model.schema().await?;

let mut member = schema
.as_struct()
.expect("model schema must be a struct")
.children
.iter()
.find(|c| {
get_selector_from_name(&c.name).expect("invalid selector for member name")
== member_selector
})
.context("member not found")?
.clone();

info!(
target: LOG_TARGET,
name = %model.name(),
entity_id = format!("{:#x}", entity_id),
member = %member.name,
"Store update member.",
);

let values_start = MEMBER_INDEX + 1;
let values_end: usize =
values_start + event.data[values_start].to_usize().context("invalid usize")?;

// Skip the length to only get the values as they will be deserialized.
let mut values = event.data[values_start + 1..=values_end].to_vec();

let tag = naming::get_tag(model.namespace(), model.name());

if !db.does_entity_exist(tag.clone(), entity_id).await? {
warn!(
target: LOG_TARGET,
tag,
entity_id = format!("{:#x}", entity_id),
"Entity not found, must be set before updating a member.",
);

return Ok(());
}

member.ty.deserialize(&mut values)?;

db.set_model_member(&schema.name(), entity_id, false, &member, event_id, block_timestamp)
.await?;
Ok(())
}
}
Loading

0 comments on commit f490222

Please sign in to comment.