fix: fetch more than one prev event

next
Timo Kösters 2021-08-14 21:56:15 +02:00
parent 1d46569929
commit ecd1e45a44
No known key found for this signature in database
GPG Key ID: 356E705610F626D5
1 changed files with 389 additions and 356 deletions

View File

@ -867,17 +867,19 @@ pub async fn handle_incoming_pdu<'a>(
.map_err(|_| "Failed to ask database for event.".to_owned())? .map_err(|_| "Failed to ask database for event.".to_owned())?
.ok_or_else(|| "Failed to find create event in db.".to_owned())?; .ok_or_else(|| "Failed to find create event in db.".to_owned())?;
let (incoming_pdu, val) = handle_outlier_pdu(origin, &create_event, event_id, room_id, value, db, pub_key_map).await?; let (incoming_pdu, val) = handle_outlier_pdu(
origin,
&create_event,
event_id,
room_id,
value,
db,
pub_key_map,
)
.await?;
// 8. if not timeline event: stop // 8. if not timeline event: stop
if !is_timeline_event if !is_timeline_event {
|| incoming_pdu.origin_server_ts
< db.rooms
.first_pdu_in_room(&room_id)
.map_err(|_| "Error loading first room event.".to_owned())?
.expect("Room exists")
.origin_server_ts
{
return Ok(None); return Ok(None);
} }
@ -893,16 +895,45 @@ pub async fn handle_incoming_pdu<'a>(
&room_id, &room_id,
pub_key_map, pub_key_map,
) )
.await.pop() { .await
todo_timeline_stack.push((pdu, json)); .pop()
{
if incoming_pdu.origin_server_ts
> db.rooms
.first_pdu_in_room(&room_id)
.map_err(|_| "Error loading first room event.".to_owned())?
.expect("Room exists")
.origin_server_ts
{
todo_outlier_stack.extend(pdu.prev_events.iter().cloned());
todo_timeline_stack.push((pdu, json));
}
} }
} }
while let Some(prev) = todo_timeline_stack.pop() { while let Some(prev) = todo_timeline_stack.pop() {
upgrade_outlier_to_timeline_pdu(prev.0, prev.1, &create_event, origin, db, room_id, pub_key_map).await?; upgrade_outlier_to_timeline_pdu(
prev.0,
prev.1,
&create_event,
origin,
db,
room_id,
pub_key_map,
)
.await?;
} }
upgrade_outlier_to_timeline_pdu(incoming_pdu, val, &create_event, origin, db, room_id, pub_key_map).await upgrade_outlier_to_timeline_pdu(
incoming_pdu,
val,
&create_event,
origin,
db,
room_id,
pub_key_map,
)
.await
} }
fn handle_outlier_pdu<'a>( fn handle_outlier_pdu<'a>(
@ -913,7 +944,8 @@ fn handle_outlier_pdu<'a>(
value: BTreeMap<String, CanonicalJsonValue>, value: BTreeMap<String, CanonicalJsonValue>,
db: &'a Database, db: &'a Database,
pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, String>>>, pub_key_map: &'a RwLock<BTreeMap<String, BTreeMap<String, String>>>,
) -> AsyncRecursiveType<'a, StdResult<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>), String>> { ) -> AsyncRecursiveType<'a, StdResult<(Arc<PduEvent>, BTreeMap<String, CanonicalJsonValue>), String>>
{
Box::pin(async move { Box::pin(async move {
let start_time = Instant::now(); let start_time = Instant::now();
@ -928,11 +960,11 @@ fn handle_outlier_pdu<'a>(
// 2. Check signatures, otherwise drop // 2. Check signatures, otherwise drop
// 3. check content hash, redact if doesn't match // 3. check content hash, redact if doesn't match
let create_event_content = let create_event_content =
serde_json::from_value::<Raw<CreateEventContent>>(create_event.content.clone()) serde_json::from_value::<Raw<CreateEventContent>>(create_event.content.clone())
.expect("Raw::from_value always works.") .expect("Raw::from_value always works.")
.deserialize() .deserialize()
.map_err(|_| "Invalid PowerLevels event in db.".to_owned())?; .map_err(|_| "Invalid PowerLevels event in db.".to_owned())?;
let room_version_id = &create_event_content.room_version; let room_version_id = &create_event_content.room_version;
let room_version = RoomVersion::new(room_version_id).expect("room version is supported"); let room_version = RoomVersion::new(room_version_id).expect("room version is supported");
@ -1062,9 +1094,8 @@ fn handle_outlier_pdu<'a>(
.map_err(|_| "Failed to add pdu as outlier.".to_owned())?; .map_err(|_| "Failed to add pdu as outlier.".to_owned())?;
debug!("Added pdu as outlier."); debug!("Added pdu as outlier.");
Ok((incoming_pdu,val)) Ok((incoming_pdu, val))
}) })
} }
async fn upgrade_outlier_to_timeline_pdu( async fn upgrade_outlier_to_timeline_pdu(
@ -1076,381 +1107,385 @@ async fn upgrade_outlier_to_timeline_pdu(
room_id: &RoomId, room_id: &RoomId,
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, String>>>, pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, String>>>,
) -> StdResult<Option<Vec<u8>>, String> { ) -> StdResult<Option<Vec<u8>>, String> {
// 10. Fetch missing state and auth chain events by calling /state_ids at backwards extremities // 10. Fetch missing state and auth chain events by calling /state_ids at backwards extremities
// doing all the checks in this list starting at 1. These are not timeline events. // doing all the checks in this list starting at 1. These are not timeline events.
// TODO: if we know the prev_events of the incoming event we can avoid the request and build // TODO: if we know the prev_events of the incoming event we can avoid the request and build
// the state from a known point and resolve if > 1 prev_event // the state from a known point and resolve if > 1 prev_event
debug!("Requesting state at event."); debug!("Requesting state at event.");
let mut state_at_incoming_event = None; let mut state_at_incoming_event = None;
if incoming_pdu.prev_events.len() == 1 { if incoming_pdu.prev_events.len() == 1 {
let prev_event = &incoming_pdu.prev_events[0]; let prev_event = &incoming_pdu.prev_events[0];
let prev_event_sstatehash = db let prev_event_sstatehash = db
.rooms .rooms
.pdu_shortstatehash(prev_event) .pdu_shortstatehash(prev_event)
.map_err(|_| "Failed talking to db".to_owned())?; .map_err(|_| "Failed talking to db".to_owned())?;
let state = let state =
prev_event_sstatehash.map(|shortstatehash| db.rooms.state_full_ids(shortstatehash)); prev_event_sstatehash.map(|shortstatehash| db.rooms.state_full_ids(shortstatehash));
if let Some(Ok(state)) = state { if let Some(Ok(state)) = state {
warn!("Using cached state"); warn!("Using cached state");
let mut state = fetch_and_handle_outliers( let mut state = fetch_and_handle_outliers(
db, db,
origin,
&state.into_iter().collect::<Vec<_>>(),
&create_event,
&room_id,
pub_key_map,
)
.await
.into_iter()
.map(|(pdu, _)| {
(
(
pdu.kind.clone(),
pdu.state_key
.clone()
.expect("events from state_full_ids are state events"),
),
pdu,
)
})
.collect::<HashMap<_, _>>();
let prev_pdu =
db.rooms.get_pdu(prev_event).ok().flatten().ok_or_else(|| {
"Could not find prev event, but we know the state.".to_owned()
})?;
if let Some(state_key) = &prev_pdu.state_key {
state.insert((prev_pdu.kind.clone(), state_key.clone()), prev_pdu);
}
state_at_incoming_event = Some(state);
}
// TODO: set incoming_auth_events?
}
if state_at_incoming_event.is_none() {
warn!("Calling /state_ids");
// Call /state_ids to find out what the state at this pdu is. We trust the server's
// response to some extend, but we still do a lot of checks on the events
match db
.sending
.send_federation_request(
&db.globals,
origin,
get_room_state_ids::v1::Request {
room_id: &room_id,
event_id: &incoming_pdu.event_id,
},
)
.await
{
Ok(res) => {
debug!("Fetching state events at event.");
let state_vec = fetch_and_handle_outliers(
&db,
origin, origin,
&state.into_iter().collect::<Vec<_>>(), &res.pdu_ids,
&create_event, &create_event,
&room_id, &room_id,
pub_key_map, pub_key_map,
) )
.await .await;
.into_iter()
.map(|(pdu,_)| { let mut state = HashMap::new();
( for (pdu, _) in state_vec {
( match state.entry((
pdu.kind.clone(), pdu.kind.clone(),
pdu.state_key pdu.state_key
.clone() .clone()
.expect("events from state_full_ids are state events"), .ok_or_else(|| "Found non-state pdu in state events.".to_owned())?,
)) {
Entry::Vacant(v) => {
v.insert(pdu);
}
Entry::Occupied(_) => return Err(
"State event's type and state_key combination exists multiple times."
.to_owned(),
), ),
pdu, }
)
})
.collect::<HashMap<_, _>>();
let prev_pdu = db.rooms.get_pdu(prev_event).ok().flatten().ok_or_else(|| {
"Could not find prev event, but we know the state.".to_owned()
})?;
if let Some(state_key) = &prev_pdu.state_key {
state.insert((prev_pdu.kind.clone(), state_key.clone()), prev_pdu);
} }
// The original create event must still be in the state
if state
.get(&(EventType::RoomCreate, "".to_owned()))
.map(|a| a.as_ref())
!= Some(&create_event)
{
return Err("Incoming event refers to wrong create event.".to_owned());
}
debug!("Fetching auth chain events at event.");
fetch_and_handle_outliers(
&db,
origin,
&res.auth_chain_ids,
&create_event,
&room_id,
pub_key_map,
)
.await;
state_at_incoming_event = Some(state); state_at_incoming_event = Some(state);
} }
// TODO: set incoming_auth_events? Err(_) => {
} return Err("Fetching state for event failed".into());
}
};
}
if state_at_incoming_event.is_none() { let state_at_incoming_event =
warn!("Calling /state_ids"); state_at_incoming_event.expect("we always set this to some above");
// Call /state_ids to find out what the state at this pdu is. We trust the server's
// response to some extend, but we still do a lot of checks on the events
match db
.sending
.send_federation_request(
&db.globals,
origin,
get_room_state_ids::v1::Request {
room_id: &room_id,
event_id: &incoming_pdu.event_id,
},
)
.await
{
Ok(res) => {
debug!("Fetching state events at event.");
let state_vec = fetch_and_handle_outliers(
&db,
origin,
&res.pdu_ids,
&create_event,
&room_id,
pub_key_map,
)
.await;
let mut state = HashMap::new(); // 11. Check the auth of the event passes based on the state of the event
for (pdu, _) in state_vec {
match state.entry((pdu.kind.clone(), pdu.state_key.clone().ok_or_else(|| "Found non-state pdu in state events.".to_owned())?)) {
Entry::Vacant(v) => {
v.insert(pdu);
}
Entry::Occupied(_) => {
return Err(
"State event's type and state_key combination exists multiple times.".to_owned(),
)
}
}
}
// The original create event must still be in the state
if state
.get(&(EventType::RoomCreate, "".to_owned()))
.map(|a| a.as_ref())
!= Some(&create_event)
{
return Err("Incoming event refers to wrong create event.".to_owned());
}
debug!("Fetching auth chain events at event.");
fetch_and_handle_outliers(
&db,
origin,
&res.auth_chain_ids,
&create_event,
&room_id,
pub_key_map,
)
.await;
state_at_incoming_event = Some(state);
}
Err(_) => {
return Err("Fetching state for event failed".into());
}
};
}
let state_at_incoming_event =
state_at_incoming_event.expect("we always set this to some above");
// 11. Check the auth of the event passes based on the state of the event
let create_event_content = let create_event_content =
serde_json::from_value::<Raw<CreateEventContent>>(create_event.content.clone()) serde_json::from_value::<Raw<CreateEventContent>>(create_event.content.clone())
.expect("Raw::from_value always works.") .expect("Raw::from_value always works.")
.deserialize() .deserialize()
.map_err(|_| "Invalid PowerLevels event in db.".to_owned())?; .map_err(|_| "Invalid PowerLevels event in db.".to_owned())?;
let room_version_id = &create_event_content.room_version; let room_version_id = &create_event_content.room_version;
let room_version = RoomVersion::new(room_version_id).expect("room version is supported"); let room_version = RoomVersion::new(room_version_id).expect("room version is supported");
// If the previous event was the create event special rules apply // If the previous event was the create event special rules apply
let previous_create = if incoming_pdu.auth_events.len() == 1 let previous_create = if incoming_pdu.auth_events.len() == 1
&& incoming_pdu.prev_events == incoming_pdu.auth_events && incoming_pdu.prev_events == incoming_pdu.auth_events
{ {
db.rooms db.rooms
.get_pdu(&incoming_pdu.auth_events[0]) .get_pdu(&incoming_pdu.auth_events[0])
.map_err(|e| e.to_string())? .map_err(|e| e.to_string())?
.filter(|maybe_create| **maybe_create == *create_event) .filter(|maybe_create| **maybe_create == *create_event)
} else { } else {
None None
}; };
if !state_res::event_auth::auth_check(
&room_version,
&incoming_pdu,
previous_create.clone(),
&state_at_incoming_event,
None, // TODO: third party invite
)
.map_err(|_e| "Auth check failed.".to_owned())?
{
return Err("Event has failed auth check with state at the event.".into());
}
debug!("Auth check succeeded.");
if !state_res::event_auth::auth_check( // We start looking at current room state now, so lets lock the room
&room_version,
&incoming_pdu, let mutex_state = Arc::clone(
previous_create.clone(), db.globals
&state_at_incoming_event, .roomid_mutex_state
None, // TODO: third party invite .write()
) .unwrap()
.map_err(|_e| "Auth check failed.".to_owned())? .entry(room_id.clone())
{ .or_default(),
return Err("Event has failed auth check with state at the event.".into()); );
let state_lock = mutex_state.lock().await;
// Now we calculate the set of extremities this room has after the incoming event has been
// applied. We start with the previous extremities (aka leaves)
let mut extremities = db
.rooms
.get_pdu_leaves(&room_id)
.map_err(|_| "Failed to load room leaves".to_owned())?;
// Remove any forward extremities that are referenced by this incoming event's prev_events
for prev_event in &incoming_pdu.prev_events {
if extremities.contains(prev_event) {
extremities.remove(prev_event);
} }
debug!("Auth check succeeded."); }
// We start looking at current room state now, so lets lock the room // Only keep those extremities were not referenced yet
extremities.retain(|id| !matches!(db.rooms.is_event_referenced(&room_id, id), Ok(true)));
let mutex_state = Arc::clone( let mut extremity_statehashes = Vec::new();
db.globals
.roomid_mutex_state for id in &extremities {
.write() match db
.unwrap() .rooms
.entry(room_id.clone()) .get_pdu(&id)
.or_default(), .map_err(|_| "Failed to ask db for pdu.".to_owned())?
{
Some(leaf_pdu) => {
extremity_statehashes.push((
db.rooms
.pdu_shortstatehash(&leaf_pdu.event_id)
.map_err(|_| "Failed to ask db for pdu state hash.".to_owned())?
.ok_or_else(|| {
error!(
"Found extremity pdu with no statehash in db: {:?}",
leaf_pdu
);
"Found pdu with no statehash in db.".to_owned()
})?,
Some(leaf_pdu),
));
}
_ => {
error!("Missing state snapshot for {:?}", id);
return Err("Missing state snapshot.".to_owned());
}
}
}
// 12. Ensure that the state is derived from the previous current state (i.e. we calculated
// by doing state res where one of the inputs was a previously trusted set of state,
// don't just trust a set of state we got from a remote).
// We do this by adding the current state to the list of fork states
let current_statehash = db
.rooms
.current_shortstatehash(&room_id)
.map_err(|_| "Failed to load current state hash.".to_owned())?
.expect("every room has state");
let current_state = db
.rooms
.state_full(current_statehash)
.map_err(|_| "Failed to load room state.")?;
extremity_statehashes.push((current_statehash.clone(), None));
let mut fork_states = Vec::new();
for (statehash, leaf_pdu) in extremity_statehashes {
let mut leaf_state = db
.rooms
.state_full(statehash)
.map_err(|_| "Failed to ask db for room state.".to_owned())?;
if let Some(leaf_pdu) = leaf_pdu {
if let Some(state_key) = &leaf_pdu.state_key {
// Now it's the state after
let key = (leaf_pdu.kind.clone(), state_key.clone());
leaf_state.insert(key, leaf_pdu);
}
}
fork_states.push(leaf_state);
}
// We also add state after incoming event to the fork states
extremities.insert(incoming_pdu.event_id.clone());
let mut state_after = state_at_incoming_event.clone();
if let Some(state_key) = &incoming_pdu.state_key {
state_after.insert(
(incoming_pdu.kind.clone(), state_key.clone()),
incoming_pdu.clone(),
); );
let state_lock = mutex_state.lock().await; }
fork_states.push(state_after.clone());
// Now we calculate the set of extremities this room has after the incoming event has been let mut update_state = false;
// applied. We start with the previous extremities (aka leaves) // 14. Use state resolution to find new room state
let mut extremities = db let new_room_state = if fork_states.is_empty() {
.rooms return Err("State is empty.".to_owned());
.get_pdu_leaves(&room_id) } else if fork_states.iter().skip(1).all(|f| &fork_states[0] == f) {
.map_err(|_| "Failed to load room leaves".to_owned())?; // There was only one state, so it has to be the room's current state (because that is
// always included)
fork_states[0]
.iter()
.map(|(k, pdu)| (k.clone(), pdu.event_id.clone()))
.collect()
} else {
// We do need to force an update to this room's state
update_state = true;
// Remove any forward extremities that are referenced by this incoming event's prev_events let fork_states = &fork_states
for prev_event in &incoming_pdu.prev_events { .into_iter()
if extremities.contains(prev_event) { .map(|map| {
extremities.remove(prev_event); map.into_iter()
} .map(|(k, v)| (k, v.event_id.clone()))
} .collect::<StateMap<_>>()
})
.collect::<Vec<_>>();
// Only keep those extremities were not referenced yet let mut auth_chain_sets = Vec::new();
extremities.retain(|id| !matches!(db.rooms.is_event_referenced(&room_id, id), Ok(true))); for state in fork_states {
auth_chain_sets.push(
let mut extremity_statehashes = Vec::new(); get_auth_chain(state.iter().map(|(_, id)| id.clone()).collect(), db)
.map_err(|_| "Failed to load auth chain.".to_owned())?
for id in &extremities { .collect(),
match db
.rooms
.get_pdu(&id)
.map_err(|_| "Failed to ask db for pdu.".to_owned())?
{
Some(leaf_pdu) => {
extremity_statehashes.push((
db.rooms
.pdu_shortstatehash(&leaf_pdu.event_id)
.map_err(|_| "Failed to ask db for pdu state hash.".to_owned())?
.ok_or_else(|| {
error!(
"Found extremity pdu with no statehash in db: {:?}",
leaf_pdu
);
"Found pdu with no statehash in db.".to_owned()
})?,
Some(leaf_pdu),
));
}
_ => {
error!("Missing state snapshot for {:?}", id);
return Err("Missing state snapshot.".to_owned());
}
}
}
// 12. Ensure that the state is derived from the previous current state (i.e. we calculated
// by doing state res where one of the inputs was a previously trusted set of state,
// don't just trust a set of state we got from a remote).
// We do this by adding the current state to the list of fork states
let current_statehash = db
.rooms
.current_shortstatehash(&room_id)
.map_err(|_| "Failed to load current state hash.".to_owned())?
.expect("every room has state");
let current_state = db
.rooms
.state_full(current_statehash)
.map_err(|_| "Failed to load room state.")?;
extremity_statehashes.push((current_statehash.clone(), None));
let mut fork_states = Vec::new();
for (statehash, leaf_pdu) in extremity_statehashes {
let mut leaf_state = db
.rooms
.state_full(statehash)
.map_err(|_| "Failed to ask db for room state.".to_owned())?;
if let Some(leaf_pdu) = leaf_pdu {
if let Some(state_key) = &leaf_pdu.state_key {
// Now it's the state after
let key = (leaf_pdu.kind.clone(), state_key.clone());
leaf_state.insert(key, leaf_pdu);
}
}
fork_states.push(leaf_state);
}
// We also add state after incoming event to the fork states
extremities.insert(incoming_pdu.event_id.clone());
let mut state_after = state_at_incoming_event.clone();
if let Some(state_key) = &incoming_pdu.state_key {
state_after.insert(
(incoming_pdu.kind.clone(), state_key.clone()),
incoming_pdu.clone(),
); );
} }
fork_states.push(state_after.clone());
let mut update_state = false; let state = match state_res::StateResolution::resolve(
// 14. Use state resolution to find new room state &room_id,
let new_room_state = if fork_states.is_empty() { room_version_id,
return Err("State is empty.".to_owned()); fork_states,
} else if fork_states.iter().skip(1).all(|f| &fork_states[0] == f) { auth_chain_sets,
// There was only one state, so it has to be the room's current state (because that is |id| {
// always included) let res = db.rooms.get_pdu(id);
fork_states[0] if let Err(e) = &res {
.iter() error!("LOOK AT ME Failed to fetch event: {}", e);
.map(|(k, pdu)| (k.clone(), pdu.event_id.clone()))
.collect()
} else {
// We do need to force an update to this room's state
update_state = true;
let fork_states = &fork_states
.into_iter()
.map(|map| {
map.into_iter()
.map(|(k, v)| (k, v.event_id.clone()))
.collect::<StateMap<_>>()
})
.collect::<Vec<_>>();
let mut auth_chain_sets = Vec::new();
for state in fork_states {
auth_chain_sets.push(
get_auth_chain(state.iter().map(|(_, id)| id.clone()).collect(), db)
.map_err(|_| "Failed to load auth chain.".to_owned())?
.collect(),
);
}
let state = match state_res::StateResolution::resolve(
&room_id,
room_version_id,
fork_states,
auth_chain_sets,
|id| {
let res = db.rooms.get_pdu(id);
if let Err(e) = &res {
error!("LOOK AT ME Failed to fetch event: {}", e);
}
res.ok().flatten()
},
) {
Ok(new_state) => new_state,
Err(_) => {
return Err("State resolution failed, either an event could not be found or deserialization".into());
} }
}; res.ok().flatten()
},
state ) {
Ok(new_state) => new_state,
Err(_) => {
return Err("State resolution failed, either an event could not be found or deserialization".into());
}
}; };
debug!("starting soft fail auth check"); state
// 13. Check if the event passes auth based on the "current state" of the room, if not "soft fail" it };
let soft_fail = !state_res::event_auth::auth_check(
&room_version,
&incoming_pdu,
previous_create,
&current_state,
None,
)
.map_err(|_e| "Auth check failed.".to_owned())?;
let mut pdu_id = None; debug!("starting soft fail auth check");
if !soft_fail { // 13. Check if the event passes auth based on the "current state" of the room, if not "soft fail" it
// Now that the event has passed all auth it is added into the timeline. let soft_fail = !state_res::event_auth::auth_check(
// We use the `state_at_event` instead of `state_after` so we accurately &room_version,
// represent the state for this event. &incoming_pdu,
pdu_id = Some( previous_create,
append_incoming_pdu( &current_state,
&db, None,
&incoming_pdu, )
val, .map_err(|_e| "Auth check failed.".to_owned())?;
extremities,
&state_at_incoming_event,
&state_lock,
)
.map_err(|_| "Failed to add pdu to db.".to_owned())?,
);
debug!("Appended incoming pdu.");
} else {
warn!("Event was soft failed: {:?}", incoming_pdu);
}
// Set the new room state to the resolved state let mut pdu_id = None;
if update_state { if !soft_fail {
db.rooms // Now that the event has passed all auth it is added into the timeline.
.force_state(&room_id, new_room_state, &db) // We use the `state_at_event` instead of `state_after` so we accurately
.map_err(|_| "Failed to set new room state.".to_owned())?; // represent the state for this event.
} pdu_id = Some(
debug!("Updated resolved state"); append_incoming_pdu(
&db,
&incoming_pdu,
val,
extremities,
&state_at_incoming_event,
&state_lock,
)
.map_err(|_| "Failed to add pdu to db.".to_owned())?,
);
debug!("Appended incoming pdu.");
} else {
warn!("Event was soft failed: {:?}", incoming_pdu);
}
if soft_fail { // Set the new room state to the resolved state
// Soft fail, we leave the event as an outlier but don't add it to the timeline if update_state {
return Err("Event has been soft failed".into()); db.rooms
} .force_state(&room_id, new_room_state, &db)
.map_err(|_| "Failed to set new room state.".to_owned())?;
}
debug!("Updated resolved state");
// Event has passed all auth/stateres checks if soft_fail {
drop(state_lock); // Soft fail, we leave the event as an outlier but don't add it to the timeline
Ok(pdu_id) return Err("Event has been soft failed".into());
}
// Event has passed all auth/stateres checks
drop(state_lock);
Ok(pdu_id)
} }
/// Find the event and auth it. Once the event is validated (steps 1 - 8) /// Find the event and auth it. Once the event is validated (steps 1 - 8)
@ -1535,9 +1570,7 @@ pub(crate) fn fetch_and_handle_outliers<'a>(
) )
.await .await
{ {
Ok((pdu, json)) => { Ok((pdu, json)) => (pdu, Some(json)),
(pdu, Some(json))
}
Err(e) => { Err(e) => {
warn!("Authentication of event {} failed: {:?}", id, e); warn!("Authentication of event {} failed: {:?}", id, e);
back_off(id.clone()); back_off(id.clone());