@ -509,7 +509,7 @@ pub async fn send_transaction_message_route<'a>(
return Err ( Error ::bad_config ( "Federation is disabled." ) ) ;
}
// dbg!(&*body);
info ! ( "Incoming PDUs: {:?}" , & body . pdus ) ;
for edu in & body . edus {
match serde_json ::from_str ::< send_transaction_message ::v1 ::Edu > ( edu . json ( ) . get ( ) ) {
@ -600,37 +600,11 @@ pub async fn send_transaction_message_route<'a>(
// events over federation. For example, the Federation API's /send endpoint would
// discard the event whereas the Client Server API's /send/{eventType} endpoint
// would return a M_BAD_JSON error.
' main_pdu_loop : for ( event_id , room_id , value ) in pdus_to_resolve {
' main_pdu_loop : for ( event_id , _room_id , value ) in pdus_to_resolve {
info ! ( "Working on incoming pdu: {:?}" , value ) ;
let server_name = & body . body . origin ;
let mut pub_key_map = BTreeMap ::new ( ) ;
if let Some ( CanonicalJsonValue ::String ( sender ) ) = value . get ( "sender" ) {
let sender =
UserId ::try_from ( sender . as_str ( ) ) . expect ( "All PDUs have a valid sender field" ) ;
let origin = sender . server_name ( ) ;
let keys = match fetch_signing_keys ( & db , & room_id , origin ) . await {
Ok ( keys ) = > keys ,
Err ( _ ) = > {
resolved_map . insert (
event_id ,
Err ( "Could not find signing keys for this server" . to_string ( ) ) ,
) ;
continue ;
}
} ;
pub_key_map . insert (
origin . to_string ( ) ,
keys . into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v . key ) )
. collect ( ) ,
) ;
} else {
resolved_map . insert ( event_id , Err ( "No field `signatures` in JSON" . to_string ( ) ) ) ;
continue ;
}
// TODO: make this persist but not a DB Tree...
// This is all the auth_events that have been recursively fetched so they don't have to be
// deserialized over and over again. This could potentially also be some sort of trie (suffix tree)
@ -645,11 +619,11 @@ pub async fn send_transaction_message_route<'a>(
// 7. if not timeline event: stop
// TODO; 8. fetch any missing prev events doing all checks listed here starting at 1. These are timeline events
// the events found in step 8 can be authed/resolved and appended to the DB
let ( pdu , previous ) : ( Arc < PduEvent > , Vec < Arc < PduEvent > > ) = match validate_event (
let ( pdu , previous _create ) : ( Arc < PduEvent > , Option < Arc < PduEvent > > ) = match validate_event (
& db ,
value ,
event_id . clone ( ) ,
& pub_key_map ,
& mut pub_key_map ,
server_name ,
// All the auth events gathered will be here
& mut auth_cache ,
@ -662,15 +636,11 @@ pub async fn send_transaction_message_route<'a>(
continue ;
}
} ;
let single_prev = if previous . len ( ) = = 1 {
previous . first ( ) . cloned ( )
} else {
None
} ;
info ! ( "Validated event." ) ;
// 6. persist the event as an outlier.
db . rooms . append_pdu_outlier ( & pdu ) ? ;
db . rooms . add_pdu_outlier ( & pdu ) ? ;
info ! ( "Added pdu as outlier." ) ;
// Step 9. fetch missing state by calling /state_ids at backwards extremities doing all
// the checks in this list starting at 1. These are not timeline events.
@ -679,6 +649,7 @@ pub async fn send_transaction_message_route<'a>(
//
// 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
info ! ( "Requesting state at event." ) ;
let ( state_at_event , incoming_auth_events ) : ( StateMap < Arc < PduEvent > > , Vec < Arc < PduEvent > > ) =
match db
. sending
@ -693,14 +664,20 @@ pub async fn send_transaction_message_route<'a>(
. await
{
Ok ( res ) = > {
let state = fetch_events (
info ! ( "Fetching state events at event." ) ;
let state = match fetch_events (
& db ,
server_name ,
& pub_key_map ,
& mut pub_key_map ,
& res . pdu_ids ,
& mut auth_cache ,
)
. await ? ;
. await
{
Ok ( state ) = > state ,
Err ( _ ) = > continue ,
} ;
// Sanity check: there are no conflicting events in the state we received
let mut seen = BTreeSet ::new ( ) ;
for ev in & state {
@ -716,17 +693,21 @@ pub async fn send_transaction_message_route<'a>(
. map ( | pdu | ( ( pdu . kind . clone ( ) , pdu . state_key . clone ( ) ) , pdu ) )
. collect ( ) ;
(
state ,
fetch_events (
let incoming_auth_events = match fetch_events (
& db ,
server_name ,
& pub_key_map ,
& mut pub_key_map ,
& res . auth_chain_ids ,
& mut auth_cache ,
)
. await ? ,
)
. await
{
Ok ( state ) = > state ,
Err ( _ ) = > continue ,
} ;
info ! ( "Fetching auth events of state events at event." ) ;
( state , incoming_auth_events )
}
Err ( _ ) = > {
resolved_map . insert (
@ -741,7 +722,7 @@ pub async fn send_transaction_message_route<'a>(
if ! state_res ::event_auth ::auth_check (
& RoomVersionId ::Version6 ,
& pdu ,
single_ prev. clone ( ) ,
previous_create . clone ( ) ,
& state_at_event ,
None , // TODO: third party invite
)
@ -754,6 +735,7 @@ pub async fn send_transaction_message_route<'a>(
) ;
continue ;
}
info ! ( "Auth check succeeded." ) ;
// End of step 10.
// 12. check if the event passes auth based on the "current state" of the room, if not "soft fail" it
@ -764,10 +746,12 @@ pub async fn send_transaction_message_route<'a>(
. map ( | ( k , v ) | ( ( k . 0 , Some ( k . 1 ) ) , Arc ::new ( v ) ) )
. collect ( ) ;
info ! ( "current state: {:#?}" , current_state ) ;
if ! state_res ::event_auth ::auth_check (
& RoomVersionId ::Version6 ,
& pdu ,
single_prev. clone ( ) ,
previous_create ,
& current_state ,
None ,
)
@ -780,6 +764,7 @@ pub async fn send_transaction_message_route<'a>(
) ;
continue ;
} ;
info ! ( "Auth check with current state succeeded." ) ;
// Step 11. 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)
@ -787,7 +772,10 @@ pub async fn send_transaction_message_route<'a>(
// calculate_forward_extremities takes care of adding the current state if not already in the state sets
// it also calculates the new pdu leaves for the `roomid_pduleaves` DB Tree.
let extremities = match calculate_forward_extremities ( & db , & pdu ) . await {
Ok ( fork_ids ) = > fork_ids ,
Ok ( fork_ids ) = > {
info ! ( "Calculated new forward extremities: {:?}" , fork_ids ) ;
fork_ids
}
Err ( _ ) = > {
resolved_map . insert ( event_id , Err ( "Failed to gather forward extremities" . into ( ) ) ) ;
continue ;
@ -836,7 +824,6 @@ pub async fn send_transaction_message_route<'a>(
// We do need to force an update to this rooms state
update_state = true ;
// TODO: remove this is for current debugging Jan, 15 2021
let mut auth_events = vec! [ ] ;
for map in & fork_states {
let mut state_auth = vec! [ ] ;
@ -877,6 +864,8 @@ pub async fn send_transaction_message_route<'a>(
. map ( | ( _ , pdu ) | ( pdu . event_id ( ) . clone ( ) , pdu ) ) ,
) ;
info ! ( "auth events: {:?}" , auth_cache ) ;
let res = match state_res ::StateResolution ::resolve (
pdu . room_id ( ) ,
& RoomVersionId ::Version6 ,
@ -927,6 +916,7 @@ pub async fn send_transaction_message_route<'a>(
// We use the `state_at_event` instead of `state_after` so we accurately
// represent the state for this event.
append_incoming_pdu ( & db , & pdu , & extremities , & state_at_event ) ? ;
info ! ( "Appended incoming pdu." ) ;
// Set the new room state to the resolved state
update_resolved_state (
@ -938,6 +928,7 @@ pub async fn send_transaction_message_route<'a>(
None
} ,
) ? ;
info ! ( "Updated resolved state" ) ;
// Event has passed all auth/stateres checks
}
@ -962,17 +953,52 @@ type AsyncRecursiveResult<'a, T> = Pin<Box<dyn Future<Output = StdResult<T, Stri
/// 5. reject "due to auth events" if the event doesn't pass auth based on the auth events
/// 7. if not timeline event: stop
/// 8. fetch any missing prev events doing all checks listed here starting at 1. These are timeline events
#[ tracing::instrument(skip(db)) ]
fn validate_event < ' a > (
db : & ' a Database ,
value : CanonicalJsonObject ,
event_id : EventId ,
pub_key_map : & ' a PublicKeyMap,
pub_key_map : & ' a mut PublicKeyMap,
origin : & ' a ServerName ,
auth_cache : & ' a mut EventMap < Arc < PduEvent > > ,
) -> AsyncRecursiveResult < ' a , ( Arc < PduEvent > , Vec < Arc < PduEvent > > ) > {
) -> AsyncRecursiveResult < ' a , ( Arc < PduEvent > , Option < Arc < PduEvent > > ) > {
Box ::pin ( async move {
for signature_server in match value
. get ( "signatures" )
. ok_or_else ( | | "No signatures in server response pdu." . to_string ( ) ) ?
{
CanonicalJsonValue ::Object ( map ) = > map ,
_ = > return Err ( "Invalid signatures object in server response pdu." . to_string ( ) ) ,
}
. keys ( )
{
info ! ( "Fetching signing keys for {}" , signature_server ) ;
let keys = match fetch_signing_keys (
& db ,
& Box ::< ServerName > ::try_from ( & * * signature_server ) . map_err ( | _ | {
"Invalid servername in signatures of server response pdu." . to_string ( )
} ) ? ,
)
. await
{
Ok ( keys ) = > {
info ! ( "Keys: {:?}" , keys ) ;
keys
}
Err ( _ ) = > {
return Err (
"Signature verification failed: Could not fetch signing key." . to_string ( ) ,
) ;
}
} ;
pub_key_map . insert ( signature_server . clone ( ) , keys ) ;
info ! ( "Fetched signing keys" ) ;
}
let mut val =
match ruma ::signatures ::verify_event ( pub_key_map , & value , & RoomVersionId ::Version6 ) {
match ruma ::signatures ::verify_event ( pub_key_map , & value , & RoomVersionId ::Version 5 ) {
Ok ( ver ) = > {
if let ruma ::signatures ::Verified ::Signatures = ver {
match ruma ::signatures ::redact ( & value , & RoomVersionId ::Version6 ) {
@ -1000,26 +1026,34 @@ fn validate_event<'a>(
)
. map_err ( | _ | "Event is not a valid PDU" . to_string ( ) ) ? ;
info ! ( "Fetching auth events." ) ;
fetch_check_auth_events ( db , origin , pub_key_map , & pdu . auth_events , auth_cache )
. await
. map_err ( | e | e . to_string ( ) ) ? ;
let pdu = Arc ::new ( pdu . clone ( ) ) ;
/*
// 8. fetch any missing prev events doing all checks listed here starting at 1. These are timeline events
let previous = fetch_events ( & db , origin , & pub_key_map , & pdu . prev_events , auth_cache )
info ! ( "Fetching prev events." ) ;
let previous = fetch_events ( & db , origin , pub_key_map , & pdu . prev_events , auth_cache )
. await
. map_err ( | e | e . to_string ( ) ) ? ;
* /
// if the previous event was the create event special rules apply
let previous_create = if pdu . auth_events . len ( ) = = 1 & & pdu . prev_events = = pdu . auth_events {
auth_cache . get ( & pdu . auth_events [ 0 ] ) . cloned ( )
} else {
None
} ;
// Check that the event passes auth based on the auth_events
info ! ( "Checking auth." ) ;
let is_authed = state_res ::event_auth ::auth_check (
& RoomVersionId ::Version6 ,
& pdu ,
if previous . len ( ) = = 1 {
previous . first ( ) . cloned ( )
} else {
None
} ,
previous_create . clone ( ) ,
& pdu . auth_events
. iter ( )
. map ( | id | {
@ -1039,39 +1073,20 @@ fn validate_event<'a>(
return Err ( "Event has failed auth check with auth events" . to_string ( ) ) ;
}
Ok ( ( pdu , previous ) )
info ! ( "Validation successful." ) ;
Ok ( ( pdu , previous_create ) )
} )
}
/// TODO: don't add as outlier if event is fetched as a result of gathering auth_events
/// The check in `fetch_check_auth_events` is that a complete chain is found for the
/// events `auth_events`. If the chain is found to have any missing events it fails.
#[ tracing::instrument(skip(db)) ]
async fn fetch_check_auth_events (
db : & Database ,
origin : & ServerName ,
key_map : & PublicKeyMap,
key_map : & mut PublicKeyMap,
event_ids : & [ EventId ] ,
auth_cache : & mut EventMap < Arc < PduEvent > > ,
) -> Result < ( ) > {
let mut stack = event_ids . to_vec ( ) ;
// DFS for auth event chain
while ! stack . is_empty ( ) {
let ev_id = stack . pop ( ) . unwrap ( ) ;
if auth_cache . contains_key ( & ev_id ) {
continue ;
}
// TODO: Batch these async calls so we can wait on multiple at once
let ev = fetch_events ( db , origin , key_map , & [ ev_id . clone ( ) ] , auth_cache )
. await
. map ( | mut vec | {
vec . pop ( )
. ok_or_else ( | | Error ::Conflict ( "Event was not found in fetch_events" ) )
} ) ? ? ;
stack . extend ( ev . auth_events ( ) ) ;
}
fetch_events ( db , origin , key_map , event_ids , auth_cache ) . await ? ;
Ok ( ( ) )
}
@ -1086,21 +1101,31 @@ async fn fetch_check_auth_events(
///
/// If the event is unknown to the `auth_cache` it is added. This guarantees that any
/// event we need to know of will be present.
#[ tracing::instrument(skip(db)) ]
pub ( crate ) async fn fetch_events (
db : & Database ,
origin : & ServerName ,
key_map : & PublicKeyMap,
key_map : & mut PublicKeyMap,
events : & [ EventId ] ,
auth_cache : & mut EventMap < Arc < PduEvent > > ,
) -> Result < Vec < Arc < PduEvent > > > {
let mut pdus = vec! [ ] ;
for id in events {
info ! ( "Fetching event: {}" , id ) ;
let pdu = match auth_cache . get ( id ) {
Some ( pdu ) = > pdu . clone ( ) ,
Some ( pdu ) = > {
info ! ( "Event found in cache" ) ;
pdu . clone ( )
}
// `get_pdu` checks the outliers tree for us
None = > match db . rooms . get_pdu ( & id ) ? {
Some ( pdu ) = > Arc ::new ( pdu ) ,
None = > match db
Some ( pdu ) = > {
info ! ( "Event found in outliers" ) ;
Arc ::new ( pdu )
}
None = > {
info ! ( "Fetching event over federation" ) ;
match db
. sending
. send_federation_request (
& db . globals ,
@ -1110,20 +1135,24 @@ pub(crate) async fn fetch_events(
. await
{
Ok ( res ) = > {
let ( event_id , value ) = crate ::pdu ::gen_event_id_canonical_json ( & res . pdu ) ;
info ! ( "Got event over federation: {:?}" , res ) ;
let ( event_id , value ) =
crate ::pdu ::gen_event_id_canonical_json ( & res . pdu ) ;
let ( pdu , _ ) =
validate_event ( db , value , event_id , key_map , origin , auth_cache )
. await
. map_err ( | e | {
error ! ( " {:?}", e ) ;
error ! ( " ERROR: {:?}", e ) ;
Error ::Conflict ( "Authentication of event failed" )
} ) ? ;
db . rooms . append_pdu_outlier ( & pdu ) ? ;
info ! ( "Added fetched pdu as outlier." ) ;
db . rooms . add_pdu_outlier ( & pdu ) ? ;
pdu
}
Err ( _ ) = > return Err ( Error ::BadServerResponse ( "Failed to fetch event" ) ) ,
} ,
}
}
} ,
} ;
auth_cache . entry ( id . clone ( ) ) . or_insert_with ( | | pdu . clone ( ) ) ;
@ -1134,14 +1163,23 @@ pub(crate) async fn fetch_events(
/// Search the DB for the signing keys of the given server, if we don't have them
/// fetch them from the server and save to our DB.
#[ tracing::instrument(skip(db)) ]
pub ( crate ) async fn fetch_signing_keys (
db : & Database ,
room_id : & RoomId ,
origin : & ServerName ,
) -> Result < BTreeMap < ServerSigningKeyId , VerifyKey > > {
) -> Result < BTreeMap < String , String > > {
let mut result = BTreeMap ::new ( ) ;
match db . globals . signing_keys_for ( origin ) ? {
keys if ! keys . is_empty ( ) = > Ok ( keys ) ,
keys if ! keys . is_empty ( ) = > {
info ! ( "we knew the signing keys already: {:?}" , keys ) ;
Ok ( keys
. into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v . key ) )
. collect ( ) )
}
_ = > {
info ! ( "Asking {} for it's signing key" , origin ) ;
match db
. sending
. send_federation_request ( & db . globals , origin , get_server_keys ::v2 ::Request ::new ( ) )
@ -1149,13 +1187,24 @@ pub(crate) async fn fetch_signing_keys(
{
Ok ( keys ) = > {
db . globals . add_signing_key ( origin , & keys . server_key ) ? ;
Ok ( keys . server_key . verify_keys )
result . extend (
keys . server_key
. verify_keys
. into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v . key ) ) ,
) ;
result . extend (
keys . server_key
. old_verify_keys
. into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v . key ) ) ,
) ;
return Ok ( result ) ;
}
_ = > {
for server in db . rooms . room_servers ( room_id ) . filter (
| ser | matches! ( ser , Ok ( s ) if db . globals . trusted_servers ( ) . contains ( s ) ) ,
) {
let server = server ? ;
for server in db . globals . trusted_servers ( ) {
info ! ( "Asking {} for {}'s signing key" , server , origin ) ;
if let Ok ( keys ) = db
. sending
. send_federation_request (
@ -1170,30 +1219,21 @@ pub(crate) async fn fetch_signing_keys(
)
. await
{
let mut trust = 0 ;
let keys : Vec < ServerSigningKeys > = keys . server_keys ;
let key = keys . iter ( ) . fold ( None , | mut key , next | {
if let Some ( verified ) = & key {
// rustc cannot elide this type for some reason
let v : & ServerSigningKeys = verified ;
if v . verify_keys
. iter ( )
. zip ( next . verify_keys . iter ( ) )
. all ( | ( a , b ) | a . 1. key = = b . 1. key )
{
trust + = 1 ;
}
} else {
key = Some ( next . clone ( ) )
}
key
} ) ;
if trust = = ( keys . len ( ) - 1 ) & & key . is_some ( ) {
let k = key . unwrap ( ) ;
info ! ( "Got signing keys: {:?}" , keys ) ;
for k in keys . server_keys . into_iter ( ) {
db . globals . add_signing_key ( origin , & k ) ? ;
return Ok ( k . verify_keys ) ;
result . extend (
k . verify_keys
. into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v . key ) ) ,
) ;
result . extend (
k . old_verify_keys
. into_iter ( )
. map ( | ( k , v ) | ( k . to_string ( ) , v . key ) ) ,
) ;
}
return Ok ( result ) ;
}
}
Err ( Error ::BadServerResponse (
@ -1211,6 +1251,7 @@ pub(crate) async fn fetch_signing_keys(
/// 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).
///
/// The state snapshot of the incoming event __needs__ to be added to the resulting list.
#[ tracing::instrument(skip(db)) ]
pub ( crate ) async fn calculate_forward_extremities (
db : & Database ,
pdu : & PduEvent ,
@ -1261,6 +1302,7 @@ pub(crate) async fn calculate_forward_extremities(
///
/// This guarantees that the incoming event will be in the state sets (at least our servers
/// and the sending server).
#[ tracing::instrument(skip(db)) ]
pub ( crate ) async fn build_forward_extremity_snapshots (
db : & Database ,
pdu : Arc < PduEvent > ,
@ -1275,12 +1317,14 @@ pub(crate) async fn build_forward_extremity_snapshots(
let mut includes_current_state = false ;
let mut fork_states = BTreeSet ::new ( ) ;
for id in current_leaves {
if id = = & pdu . event_id {
continue ;
}
match db . rooms . get_pdu_id ( id ) ? {
// We can skip this because it is handled outside of this function
// The current server state and incoming event state are built to be
// the state after.
// This would be the incoming state from the server.
Some ( _ ) if id = = pdu . event_id ( ) = > { }
Some ( pduid ) if db . rooms . get_pdu_from_id ( & pduid ) ? . is_some ( ) = > {
let state_hash = db
. rooms
@ -1308,40 +1352,7 @@ pub(crate) async fn build_forward_extremity_snapshots(
}
_ = > {
error ! ( "Missing state snapshot for {:?} - {:?}" , id , pdu . kind ( ) ) ;
let res = db
. sending
. send_federation_request (
& db . globals ,
origin ,
get_room_state_ids ::v1 ::Request {
room_id : pdu . room_id ( ) ,
event_id : id ,
} ,
)
. await ? ;
// TODO: This only adds events to the auth_cache, there is for sure a better way to
// do this...
fetch_events ( & db , origin , pub_key_map , & res . auth_chain_ids , auth_cache ) . await ? ;
let mut state_before =
fetch_events ( & db , origin , pub_key_map , & res . pdu_ids , auth_cache )
. await ?
. into_iter ( )
. map ( | pdu | ( ( pdu . kind . clone ( ) , pdu . state_key . clone ( ) ) , pdu ) )
. collect ::< StateMap < _ > > ( ) ;
if let Some ( pdu ) = fetch_events ( db , origin , pub_key_map , & [ id . clone ( ) ] , auth_cache )
. await ?
. pop ( )
{
let key = ( pdu . kind . clone ( ) , pdu . state_key ( ) ) ;
state_before . insert ( key , pdu ) ;
}
// Now it's the state after
fork_states . insert ( state_before ) ;
return Err ( Error ::BadDatabase ( "Missing state snapshot." ) ) ;
}
}
}
@ -1353,9 +1364,11 @@ pub(crate) async fn build_forward_extremity_snapshots(
fork_states . insert ( current_state ) ;
}
info ! ( "Fork states: {:?}" , fork_states ) ;
Ok ( fork_states )
}
#[ tracing::instrument(skip(db)) ]
pub ( crate ) fn update_resolved_state (
db : & Database ,
room_id : & RoomId ,
@ -1366,23 +1379,15 @@ pub(crate) fn update_resolved_state(
if let Some ( state ) = state {
let mut new_state = HashMap ::new ( ) ;
for ( ( ev_type , state_k ) , pdu ) in state {
match db . rooms . get_pdu_id ( pdu . event_id ( ) ) ? {
Some ( pduid ) = > {
let long_id = db . rooms . get_long_id ( & pdu . event_id ) ? ;
new_state . insert (
(
ev_type ,
state_k . ok_or_else ( | | {
Error ::Conflict ( "State contained non state event" )
} ) ? ,
state_k . ok_or_else ( | | Error ::Conflict ( "State contained non state event" ) ) ? ,
) ,
pduid . to_vec ( ) ,
long_id ,
) ;
}
None = > {
error ! ( "We are missing a state event for the current room state." ) ;
}
}
}
db . rooms . force_state ( room_id , new_state , & db . globals ) ? ;
}
@ -1392,6 +1397,7 @@ pub(crate) fn update_resolved_state(
/// Append the incoming event setting the state snapshot to the state from the
/// server that sent the event.
#[ tracing::instrument(skip(db)) ]
pub ( crate ) fn append_incoming_pdu (
db : & Database ,
pdu : & PduEvent ,
@ -1402,8 +1408,7 @@ pub(crate) fn append_incoming_pdu(
// We can tell if we need to do this based on wether state resolution took place or not
let mut new_state = HashMap ::new ( ) ;
for ( ( ev_type , state_k ) , state_pdu ) in state {
match db . rooms . get_pdu_id ( state_pdu . event_id ( ) ) ? {
Some ( state_pduid ) = > {
let long_id = db . rooms . get_long_id ( state_pdu . event_id ( ) ) ? ;
new_state . insert (
(
ev_type . clone ( ) ,
@ -1411,12 +1416,9 @@ pub(crate) fn append_incoming_pdu(
. clone ( )
. ok_or_else ( | | Error ::Conflict ( "State contained non state event" ) ) ? ,
) ,
state_pdu id. to_vec ( ) ,
long_ id. to_vec ( ) ,
) ;
}
None = > error ! ( "We are missing a state event for the incoming event snapshot" ) ,
}
}
db . rooms
. force_state ( pdu . room_id ( ) , new_state , & db . globals ) ? ;