lexi_topo_sort needs to return a neg power_level to sort properly

All tests pass!!! Changed println! to logger calls.
This commit is contained in:
Devin R 2020-07-23 09:38:47 -04:00
parent a0db51b3bd
commit 106cab46bc
3 changed files with 225 additions and 75 deletions

View File

@ -140,13 +140,15 @@ impl StateResolution {
// TODO make sure each conflicting event is in event_map??
// synapse says `full_set = {eid for eid in full_conflicted_set if eid in event_map}`
all_conflicted.retain(|id| event_map.contains_key(id));
println!(
tracing::debug!(
"ALL {:?}",
all_conflicted
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
);
// get only the power events with a state_key: "" or ban/kick event (sender != state_key)
let power_events = all_conflicted
.iter()
@ -154,7 +156,7 @@ impl StateResolution {
.cloned()
.collect::<Vec<_>>();
println!(
tracing::debug!(
"POWER {:?}",
power_events
.iter()
@ -171,7 +173,7 @@ impl StateResolution {
&all_conflicted,
);
println!(
tracing::debug!(
"SRTD {:?}",
sorted_power_levels
.iter()
@ -209,7 +211,7 @@ impl StateResolution {
.cloned()
.collect::<Vec<_>>();
println!(
tracing::debug!(
"LEFT {:?}",
events_to_resolve
.iter()
@ -224,7 +226,7 @@ impl StateResolution {
let sorted_left_events =
self.mainline_sort(room_id, &events_to_resolve, power_event, &event_map, store);
println!(
tracing::debug!(
"SORTED LEFT {:?}",
sorted_left_events
.iter()
@ -330,7 +332,7 @@ impl StateResolution {
let mut event_to_pl = BTreeMap::new();
for (idx, event_id) in graph.keys().enumerate() {
let pl = self.get_power_level_for_sender(room_id, &event_id, event_map, store);
println!("{} power level {}", event_id.to_string(), pl);
tracing::info!("{} power level {}", event_id.to_string(), pl);
event_to_pl.insert(event_id.clone(), pl);
@ -345,10 +347,20 @@ impl StateResolution {
// tracing::debug!("{:?}", event_map.get(event_id).unwrap().origin_server_ts());
let ev = event_map.get(event_id).unwrap();
let pl = event_to_pl.get(event_id).unwrap();
tracing::debug!(
"{:?}",
(
-*pl,
ev.origin_server_ts().clone(),
ev.event_id().unwrap().to_string()
)
);
// This return value is the key used for sorting events,
// events are then sorted by power level, time,
// and lexically by event_id.
(*pl, ev.origin_server_ts().clone(), ev.event_id().cloned())
(-*pl, ev.origin_server_ts().clone(), ev.event_id().cloned())
})
}
@ -419,16 +431,12 @@ impl StateResolution {
sorted.push(node.clone());
}
// tracing::debug!(
// "{:#?}",
// sorted.iter().map(ToString::to_string).collect::<Vec<_>>()
// );
sorted
}
fn get_power_level_for_sender(
&self,
room_id: &RoomId,
_room_id: &RoomId,
event_id: &EventId,
event_map: &EventMap<StateEvent>, // TODO use event_map over store ??
store: &dyn StateStore,
@ -438,9 +446,8 @@ impl StateResolution {
let mut pl = None;
// TODO store.auth_event_ids returns "self" with the event ids is this ok
// event.auth_event_ids does not include its own event id ?
for aid in event_map.get(event_id).unwrap().auth_event_ids() {
println!("aid {}", aid.to_string());
if let Some(aev) = event_map.get(&aid) {
for aid in store.get_event(event_id).unwrap().auth_event_ids() {
if let Ok(aev) = store.get_event(&aid) {
if aev.is_type_and_key(EventType::RoomPowerLevels, "") {
pl = Some(aev);
break;
@ -449,10 +456,8 @@ impl StateResolution {
}
if pl.is_none() {
for aid in event_map.get(event_id).unwrap().auth_event_ids() {
println!("aid NONE {}", aid.to_string());
if let Some(aev) = event_map.get(&aid) {
for aid in store.get_event(event_id).unwrap().auth_event_ids() {
if let Ok(aev) = store.get_event(&aid) {
if aev.is_type_and_key(EventType::RoomCreate, "") {
if let Ok(content) = aev
.deserialize_content::<ruma::events::room::create::CreateEventContent>()
@ -478,10 +483,11 @@ impl StateResolution {
{
if let Some(ev) = event {
if let Some(user) = content.users.get(ev.sender()) {
tracing::debug!("found {} at power_level {}", ev.sender().to_string(), user);
return (*user).into();
}
}
content.state_default.into()
content.users_default.into()
} else {
0
}
@ -549,7 +555,7 @@ impl StateResolution {
/// the `resolved_power_level`.
fn mainline_sort(
&mut self,
room_id: &RoomId,
_room_id: &RoomId,
to_sort: &[EventId],
resolved_power_level: Option<&EventId>,
event_map: &EventMap<StateEvent>,
@ -571,7 +577,7 @@ impl StateResolution {
while let Some(p) = pl {
mainline.push(p.clone());
// We don't need the actual pl_ev here since we delegate to the store
let auth_events = store.auth_event_ids(room_id, &[p]).unwrap();
let auth_events = store.get_event(&p).unwrap().auth_event_ids();
pl = None;
for aid in auth_events {
let ev = store.get_event(&aid).unwrap();
@ -664,7 +670,7 @@ impl StateResolution {
fn add_event_and_auth_chain_to_graph(
&self,
room_id: &RoomId,
_room_id: &RoomId,
graph: &mut BTreeMap<EventId, Vec<EventId>>,
event_id: &EventId,
store: &dyn StateStore,
@ -677,7 +683,7 @@ impl StateResolution {
graph.entry(eid.clone()).or_insert(vec![]);
// prefer the store to event as the store filters dedups the events
// otherwise it seems we can loop forever
for aid in store.auth_event_ids(room_id, &[eid.clone()]).unwrap() {
for aid in store.get_event(&eid).unwrap().auth_event_ids() {
if auth_diff.contains(&aid) {
if !graph.contains_key(&aid) {
state.push(aid.clone());

View File

@ -44,9 +44,32 @@ impl StateEvent {
}
_ => false,
},
Pdu::RoomV3Pdu(event) => panic!(),
Pdu::RoomV3Pdu(event) => event.state_key == Some("".into()),
},
Self::Sync(any_event) => match any_event {
PduStub::RoomV1PduStub(event) => match event.kind {
EventType::RoomPowerLevels
| EventType::RoomJoinRules
| EventType::RoomCreate => event.state_key == Some("".into()),
EventType::RoomMember => {
if let Ok(content) =
serde_json::from_value::<MemberEventContent>(event.content.clone())
{
if [MembershipState::Leave, MembershipState::Ban]
.contains(&content.membership)
{
return event.sender.as_str()
// TODO does None here mean the same as state_key = ""
!= event.state_key.as_deref().unwrap_or("");
}
}
false
}
_ => false,
},
PduStub::RoomV3PduStub(event) => event.state_key == Some("".into()),
},
Self::Sync(any_event) => panic!(),
}
}
pub fn deserialize_content<C: serde::de::DeserializeOwned>(

View File

@ -32,11 +32,11 @@ fn id(id: &str) -> EventId {
fn alice() -> UserId {
UserId::try_from("@alice:foo").unwrap()
}
fn bobo() -> UserId {
UserId::try_from("@bobo:foo").unwrap()
fn bob() -> UserId {
UserId::try_from("@bob:foo").unwrap()
}
fn devin() -> UserId {
UserId::try_from("@devin:foo").unwrap()
fn charlie() -> UserId {
UserId::try_from("@charlie:foo").unwrap()
}
fn zera() -> UserId {
UserId::try_from("@zera:foo").unwrap()
@ -244,16 +244,16 @@ fn INITIAL_EVENTS() -> BTreeMap<EventId, StateEvent> {
),
to_init_pdu_event(
"IMB",
bobo(),
bob(),
EventType::RoomMember,
Some(bobo().to_string().as_str()),
Some(bob().to_string().as_str()),
member_content_join(),
),
to_init_pdu_event(
"IMC",
devin(),
charlie(),
EventType::RoomMember,
Some(devin().to_string().as_str()),
Some(charlie().to_string().as_str()),
member_content_join(),
),
to_init_pdu_event(
@ -292,7 +292,7 @@ fn do_check(events: &[StateEvent], edges: Vec<Vec<EventId>>, expected_state_ids:
// .init();
let mut resolver = StateResolution::default();
// TODO what do we fill this with, everything ??
let store = TestStore(RefCell::new(
INITIAL_EVENTS()
.values()
@ -354,16 +354,16 @@ fn do_check(events: &[StateEvent], edges: Vec<Vec<EventId>>, expected_state_ids:
.cloned()
.collect::<Vec<_>>();
// println!(
// "RESOLVING {:?}",
// state_sets
// .iter()
// .map(|map| map
// .iter()
// .map(|((t, s), id)| (t, s, id.to_string()))
// .collect::<Vec<_>>())
// .collect::<Vec<_>>()
// );
tracing::debug!(
"RESOLVING {:?}",
state_sets
.iter()
.map(|map| map
.iter()
.map(|((t, s), id)| (t, s, id.to_string()))
.collect::<Vec<_>>())
.collect::<Vec<_>>()
);
let resolved = resolver.resolve(
&room_id(),
@ -397,10 +397,6 @@ fn do_check(events: &[StateEvent], edges: Vec<Vec<EventId>>, expected_state_ids:
}
let auth_types = state_res::auth_types_for_event(fake_event);
// println!(
// "AUTH TYPES {:?}",
// auth_types.iter().map(|(t, id)| (t, id)).collect::<Vec<_>>()
// );
let mut auth_events = vec![];
for key in auth_types {
@ -469,7 +465,7 @@ fn ban_vs_power_level() {
alice(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
json!({"users": {alice(): 100, bob(): 50}}),
),
to_init_pdu_event(
"MA",
@ -482,15 +478,15 @@ fn ban_vs_power_level() {
"MB",
alice(),
EventType::RoomMember,
Some(bobo().to_string().as_str()),
Some(bob().to_string().as_str()),
member_content_ban(),
),
to_init_pdu_event(
"PB",
bobo(),
bob(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
json!({"users": {alice(): 100, bob(): 50}}),
),
];
@ -518,7 +514,7 @@ fn ban_vs_power_level() {
do_check(events, edges, expected_state_ids)
}
// #[test]
#[test]
fn topic_basic() {
let events = &[
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
@ -527,7 +523,7 @@ fn topic_basic() {
alice(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
json!({"users": {alice(): 100, bob(): 50}}),
),
to_init_pdu_event("T2", alice(), EventType::RoomTopic, Some(""), json!({})),
to_init_pdu_event(
@ -535,16 +531,16 @@ fn topic_basic() {
alice(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 0}}),
json!({"users": {alice(): 100, bob(): 0}}),
),
to_init_pdu_event(
"PAB",
bobo(),
"PB",
bob(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
json!({"users": {alice(): 100, bob(): 50}}),
),
to_init_pdu_event("T3", bobo(), EventType::RoomTopic, Some(""), json!({})),
to_init_pdu_event("T3", bob(), EventType::RoomTopic, Some(""), json!({})),
];
let edges = vec![
@ -580,14 +576,14 @@ fn topic_reset() {
alice(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
json!({"users": {alice(): 100, bob(): 50}}),
),
to_init_pdu_event("T2", bobo(), EventType::RoomTopic, Some(""), json!({})),
to_init_pdu_event("T2", bob(), EventType::RoomTopic, Some(""), json!({})),
to_init_pdu_event(
"MB",
alice(),
EventType::RoomMember,
Some(bobo().to_string().as_str()),
Some(bob().to_string().as_str()),
member_content_ban(),
),
];
@ -616,6 +612,30 @@ fn topic_reset() {
do_check(events, edges, expected_state_ids)
}
#[test]
fn test_event_map_none() {
let mut resolver = StateResolution::default();
let store = TestStore(RefCell::new(btreemap! {}));
// build up the DAG
let (state_at_bob, state_at_charlie, expected) = store.set_up();
let resolved = match resolver.resolve(
&room_id(),
&RoomVersionId::version_2(),
&[state_at_bob, state_at_charlie],
None,
&store,
) {
Ok(ResolutionResult::Resolved(state)) => state,
Err(e) => panic!("{}", e),
_ => panic!("conflicted state left"),
};
assert_eq!(expected, resolved)
}
#[test]
fn test_lexicographical_sort() {
let mut resolver = StateResolution::default();
@ -699,16 +719,10 @@ impl StateStore for TestStore {
) -> Result<Vec<EventId>, String> {
use itertools::Itertools;
// println!(
// "EVENTS FOR AUTH {:?}",
// event_ids
// .iter()
// .map(|v| v.iter().map(ToString::to_string).collect::<Vec<_>>())
// .collect::<Vec<_>>()
// );
let mut chains = vec![];
for ids in event_ids {
// TODO state store `auth_event_ids` returns self in the event ids list
// when an event returns `auth_event_ids` self is not contained
let chain = self
.auth_event_ids(room_id, &ids)?
.into_iter()
@ -719,10 +733,7 @@ impl StateStore for TestStore {
if let Some(chain) = chains.first() {
let rest = chains.iter().skip(1).flatten().cloned().collect();
let common = chain.intersection(&rest).collect::<Vec<_>>();
// println!(
// "COMMON {:?}",
// common.iter().map(ToString::to_string).collect::<Vec<_>>()
// );
Ok(chains
.iter()
.flatten()
@ -736,3 +747,113 @@ impl StateStore for TestStore {
}
}
}
impl TestStore {
pub fn set_up(&self) -> (StateMap<EventId>, StateMap<EventId>, StateMap<EventId>) {
let create_event = to_pdu_event::<EventId>(
"CREATE",
alice(),
EventType::RoomCreate,
Some(""),
json!({ "creator": alice() }),
&[],
&[],
);
let cre = create_event.event_id().unwrap().clone();
self.0
.borrow_mut()
.insert(cre.clone(), create_event.clone());
let alice_mem = to_pdu_event(
"IMA",
alice(),
EventType::RoomMember,
Some(alice().to_string().as_str()),
member_content_join(),
&[cre.clone()],
&[cre.clone()],
);
self.0
.borrow_mut()
.insert(alice_mem.event_id().unwrap().clone(), alice_mem.clone());
let join_rules = to_pdu_event(
"IJR",
alice(),
EventType::RoomJoinRules,
Some(""),
json!({ "join_rule": JoinRule::Public }),
&[cre.clone(), alice_mem.event_id().unwrap().clone()],
&[alice_mem.event_id().unwrap().clone()],
);
self.0
.borrow_mut()
.insert(join_rules.event_id().unwrap().clone(), join_rules.clone());
// Bob and Charlie join at the same time, so there is a fork
// this will be represented in the state_sets when we resolve
let bob_mem = to_pdu_event(
"IMB",
bob(),
EventType::RoomMember,
Some(bob().to_string().as_str()),
member_content_join(),
&[cre.clone(), join_rules.event_id().unwrap().clone()],
&[join_rules.event_id().unwrap().clone()],
);
self.0
.borrow_mut()
.insert(bob_mem.event_id().unwrap().clone(), bob_mem.clone());
let charlie_mem = to_pdu_event(
"IMC",
charlie(),
EventType::RoomMember,
Some(charlie().to_string().as_str()),
member_content_join(),
&[cre.clone(), join_rules.event_id().unwrap().clone()],
&[join_rules.event_id().unwrap().clone()],
);
self.0
.borrow_mut()
.insert(charlie_mem.event_id().unwrap().clone(), charlie_mem.clone());
let state_at_bob = [&create_event, &alice_mem, &join_rules, &bob_mem]
.iter()
.map(|e| {
(
(e.kind(), e.state_key().unwrap().clone()),
e.event_id().unwrap().clone(),
)
})
.collect::<BTreeMap<_, _>>();
let state_at_charlie = [&create_event, &alice_mem, &join_rules, &charlie_mem]
.iter()
.map(|e| {
(
(e.kind(), e.state_key().unwrap().clone()),
e.event_id().unwrap().clone(),
)
})
.collect::<BTreeMap<_, _>>();
let expected = [
&create_event,
&alice_mem,
&join_rules,
&bob_mem,
&charlie_mem,
]
.iter()
.map(|e| {
(
(e.kind(), e.state_key().unwrap().clone()),
e.event_id().unwrap().clone(),
)
})
.collect::<BTreeMap<_, _>>();
(state_at_bob, state_at_charlie, expected)
}
}