1#![warn(clippy::missing_docs_in_private_items)]
2
3use raiden_primitives::{
4 constants::CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
5 types::{
6 BlockHash,
7 BlockNumber,
8 },
9};
10
11use super::{
12 channel,
13 mediator,
14 secret_registry,
15 utils::{
16 self,
17 update_channel,
18 },
19};
20use crate::{
21 errors::StateTransitionError,
22 types::{
23 ActionInitTarget,
24 Block,
25 ChainState,
26 ChannelState,
27 ContractReceiveSecretReveal,
28 ErrorUnlockClaimFailed,
29 Event,
30 PaymentReceivedSuccess,
31 ReceiveLockExpired,
32 ReceiveSecretReveal,
33 ReceiveUnlock,
34 SendMessageEventInner,
35 SendSecretRequest,
36 SendSecretReveal,
37 StateChange,
38 TargetState,
39 TargetTransferState,
40 },
41 views,
42};
43
44pub(super) type TransitionResult = std::result::Result<TargetTransition, StateTransitionError>;
46
47#[derive(Debug)]
49pub struct TargetTransition {
50 pub new_state: Option<TargetTransferState>,
51 pub chain_state: ChainState,
52 pub events: Vec<Event>,
53}
54
55fn events_for_onchain_secretreveal(
58 target_state: &mut TargetTransferState,
59 channel_state: &ChannelState,
60 block_number: BlockNumber,
61 block_hash: BlockHash,
62) -> Result<Vec<Event>, String> {
63 let transfer = &target_state.transfer;
64 let expiration = transfer.lock.expiration;
65
66 let safe_to_wait =
67 mediator::is_safe_to_wait(expiration, channel_state.reveal_timeout, block_number).is_ok();
68 let secret_known_offchain =
69 channel_state.partner_state.is_secret_known_offchain(transfer.lock.secrethash);
70 let has_onchain_reveal_started = target_state.state == TargetState::OnchainSecretReveal;
71
72 if !safe_to_wait && secret_known_offchain && !has_onchain_reveal_started {
73 target_state.state = TargetState::OnchainSecretReveal;
74 let secret = match channel_state.partner_state.get_secret(transfer.lock.secrethash) {
75 Some(secret) => secret,
76 None => return Err("Secret should be known at this point".to_owned()),
77 };
78
79 return Ok(secret_registry::events_for_onchain_secretreveal(
80 channel_state,
81 secret,
82 expiration,
83 block_hash,
84 ))
85 }
86
87 Ok(vec![])
88}
89
90fn handle_init_target(
92 mut chain_state: ChainState,
93 target_state: Option<TargetTransferState>,
94 state_change: ActionInitTarget,
95) -> TransitionResult {
96 if target_state.is_some() {
97 return Ok(TargetTransition { new_state: target_state, chain_state, events: vec![] })
99 }
100
101 let transfer = &state_change.transfer;
102 let from_hop = state_change.from_hop;
103
104 let mut channel_state = match views::get_channel_by_canonical_identifier(
105 &chain_state,
106 transfer.balance_proof.canonical_identifier.clone(),
107 ) {
108 Some(channel_state) => channel_state.clone(),
109 None => return Ok(TargetTransition { new_state: None, chain_state, events: vec![] }),
110 };
111
112 let sender = match transfer.balance_proof.sender {
113 Some(sender) => sender,
114 None => return Err("Transfer sender should be set".to_owned().into()),
115 };
116 let handle_locked_transfer = channel::handle_receive_locked_transfer(
117 &mut channel_state,
118 transfer.clone(),
119 views::get_address_metadata(sender, transfer.route_states.clone()),
120 );
121 let reveal_timeout = channel_state.reveal_timeout;
122 update_channel(&mut chain_state, channel_state).map_err(Into::into)?;
123
124 let mut events = vec![];
125 let target_state = match handle_locked_transfer {
126 Ok(channel_event) => {
127 let target_state = TargetTransferState {
135 from_hop,
136 transfer: transfer.clone(),
137 secret: None,
138 state: TargetState::SecretRequest,
139 initiator_address_metadata: None,
140 };
141 events.push(channel_event);
142
143 if state_change.received_valid_secret {
144 return Ok(TargetTransition { new_state: Some(target_state), chain_state, events })
145 }
146
147 let safe_to_wait = mediator::is_safe_to_wait(
148 transfer.lock.expiration,
149 reveal_timeout,
150 chain_state.block_number,
151 )
152 .is_ok();
153 if safe_to_wait {
154 let message_identifier = chain_state.pseudo_random_number_generator.next();
155 let recipient = transfer.initiator;
156 let secret_request = SendSecretRequest {
157 inner: SendMessageEventInner {
158 recipient,
159 recipient_metadata: views::get_address_metadata(
160 recipient,
161 transfer.route_states.clone(),
162 ),
163 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
164 message_identifier,
165 },
166 payment_identifier: transfer.payment_identifier,
167 amount: transfer.lock.amount,
168 expiration: transfer.lock.expiration,
169 secrethash: transfer.lock.secrethash,
170 };
171 events.push(secret_request.into());
172 }
173 Some(target_state)
174 },
175 Err((e, err_events)) => {
176 let unlock_failed = ErrorUnlockClaimFailed {
177 identifier: transfer.payment_identifier,
178 secrethash: transfer.lock.secrethash,
179 reason: e,
180 };
181 events.push(unlock_failed.into());
182 events.extend(err_events);
183 None
184 },
185 };
186
187 Ok(TargetTransition { new_state: target_state, chain_state, events })
188}
189
190fn handle_block(
193 chain_state: ChainState,
194 target_state: Option<TargetTransferState>,
195 state_change: Block,
196) -> TransitionResult {
197 let mut target_state = match target_state {
198 Some(target_state) => target_state,
199 None => return Err("Block should be accompanied by a valid target state".to_owned().into()),
200 };
201
202 let mut events = vec![];
203
204 let transfer = &target_state.transfer;
205 let lock = &transfer.lock;
206
207 let channel_state = match views::get_channel_by_canonical_identifier(
208 &chain_state,
209 transfer.balance_proof.canonical_identifier.clone(),
210 ) {
211 Some(channel_state) => channel_state,
212 None =>
213 return Ok(TargetTransition {
214 new_state: Some(target_state),
215 chain_state,
216 events: vec![],
217 }),
218 };
219
220 let secret_known = channel_state.partner_state.is_secret_known(lock.secrethash);
221 let lock_has_expired = channel::validators::is_lock_expired(
222 &channel_state.our_state,
223 lock,
224 chain_state.block_number,
225 channel::views::get_receiver_expiration_threshold(lock.expiration),
226 )
227 .is_ok();
228
229 if lock_has_expired && target_state.state != TargetState::Expired {
230 target_state.state = TargetState::Expired;
231 events.push(
232 ErrorUnlockClaimFailed {
233 identifier: transfer.payment_identifier,
234 secrethash: transfer.lock.secrethash,
235 reason: "Lock expired".to_owned(),
236 }
237 .into(),
238 );
239 } else if secret_known {
240 events.extend(
241 events_for_onchain_secretreveal(
242 &mut target_state,
243 channel_state,
244 state_change.block_number,
245 state_change.block_hash,
246 )
247 .map_err(Into::into)?,
248 );
249 }
250
251 Ok(TargetTransition { new_state: Some(target_state), chain_state, events })
252}
253
254fn handle_offchain_secret_reveal(
256 mut chain_state: ChainState,
257 target_state: Option<TargetTransferState>,
258 state_change: ReceiveSecretReveal,
259) -> TransitionResult {
260 let mut target_state = match target_state {
261 Some(target_state) => target_state,
262 None => return Err("Block should be accompanied by a valid target state".to_owned().into()),
263 };
264
265 let mut events = vec![];
266
267 let transfer = &target_state.transfer;
268
269 let mut channel_state = match views::get_channel_by_canonical_identifier(
270 &chain_state,
271 transfer.balance_proof.canonical_identifier.clone(),
272 ) {
273 Some(channel_state) => channel_state.clone(),
274 None =>
275 return Ok(TargetTransition {
276 new_state: Some(target_state),
277 chain_state,
278 events: vec![],
279 }),
280 };
281
282 let valid_secret = utils::is_valid_secret_reveal(&state_change, transfer.lock.secrethash);
283 let has_transfer_expired = channel::validators::is_transfer_expired(
284 transfer,
285 &channel_state,
286 chain_state.block_number,
287 );
288
289 if valid_secret && !has_transfer_expired {
290 channel::register_offchain_secret(
291 &mut channel_state,
292 state_change.secret.clone(),
293 state_change.secrethash,
294 );
295 update_channel(&mut chain_state, channel_state).map_err(Into::into)?;
296
297 let from_hop = &target_state.from_hop;
298 let message_identifier = chain_state.pseudo_random_number_generator.next();
299 target_state.state = TargetState::OffchainSecretReveal;
300 target_state.secret = Some(state_change.secret.clone());
301 let recipient = from_hop.node_address;
302
303 let reveal = SendSecretReveal {
304 inner: SendMessageEventInner {
305 recipient,
306 recipient_metadata: views::get_address_metadata(
307 recipient,
308 transfer.route_states.clone(),
309 ),
310 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
311 message_identifier,
312 },
313 secret: state_change.secret,
314 secrethash: state_change.secrethash,
315 };
316
317 events.push(reveal.into());
318 }
319
320 Ok(TargetTransition { new_state: Some(target_state), chain_state, events })
321}
322
323fn handle_onchain_secret_reveal(
325 mut chain_state: ChainState,
326 target_state: Option<TargetTransferState>,
327 state_change: ContractReceiveSecretReveal,
328) -> TransitionResult {
329 let mut target_state = match target_state {
330 Some(target_state) => target_state,
331 None => return Err("Block should be accompanied by a valid target state".to_owned().into()),
332 };
333
334 let transfer = &target_state.transfer;
335
336 let mut channel_state = match views::get_channel_by_canonical_identifier(
337 &chain_state,
338 transfer.balance_proof.canonical_identifier.clone(),
339 ) {
340 Some(channel_state) => channel_state.clone(),
341 None =>
342 return Ok(TargetTransition {
343 new_state: Some(target_state),
344 chain_state,
345 events: vec![],
346 }),
347 };
348
349 let valid_secret =
350 utils::is_valid_onchain_secret_reveal(&state_change, transfer.lock.secrethash);
351
352 if valid_secret {
353 channel::register_onchain_secret(
354 &mut channel_state,
355 state_change.secret.clone(),
356 state_change.secrethash,
357 state_change.block_number,
358 true,
359 );
360 update_channel(&mut chain_state, channel_state).map_err(Into::into)?;
361
362 target_state.state = TargetState::OffchainSecretReveal;
363 target_state.secret = Some(state_change.secret);
364 }
365
366 Ok(TargetTransition { new_state: Some(target_state), chain_state, events: vec![] })
367}
368
369fn handle_lock_expired(
371 mut chain_state: ChainState,
372 target_state: Option<TargetTransferState>,
373 state_change: ReceiveLockExpired,
374) -> TransitionResult {
375 let target_state = match target_state {
376 Some(target_state) => target_state,
377 None => return Err("Block should be accompanied by a valid target state".to_owned().into()),
378 };
379
380 let transfer = &target_state.transfer;
381
382 let mut channel_state = match views::get_channel_by_canonical_identifier(
383 &chain_state,
384 transfer.balance_proof.canonical_identifier.clone(),
385 ) {
386 Some(channel_state) => channel_state.clone(),
387 None =>
388 return Ok(TargetTransition {
389 new_state: Some(target_state),
390 chain_state,
391 events: vec![],
392 }),
393 };
394
395 let sender = match transfer.balance_proof.sender {
396 Some(sender) => sender,
397 None => return Err("Transfer sender should be set".to_owned().into()),
398 };
399 let recipient_metadata = views::get_address_metadata(sender, transfer.route_states.clone());
400 let mut result = channel::handle_receive_lock_expired(
401 &mut channel_state,
402 state_change,
403 chain_state.block_number,
404 recipient_metadata,
405 )?;
406 let channel_state = match result.new_state {
407 Some(channel_state) => channel_state,
408 None =>
409 return Err("handle_receive_lock_expired should not delete channel".to_owned().into()),
410 };
411
412 update_channel(&mut chain_state, channel_state.clone()).map_err(Into::into)?;
413
414 if channel::views::get_lock(&channel_state.partner_state, transfer.lock.secrethash).is_none() {
415 let unlock_failed = ErrorUnlockClaimFailed {
416 identifier: transfer.payment_identifier,
417 secrethash: transfer.lock.secrethash,
418 reason: "Lock expired".to_owned(),
419 };
420 result.events.push(unlock_failed.into());
421 }
422
423 Ok(TargetTransition { new_state: Some(target_state), chain_state, events: result.events })
424}
425
426fn handle_unlock(
428 mut chain_state: ChainState,
429 target_state: Option<TargetTransferState>,
430 state_change: ReceiveUnlock,
431) -> TransitionResult {
432 let target_state = match target_state {
433 Some(target_state) => target_state,
434 None => return Err("Block should be accompanied by a valid target state".to_owned().into()),
435 };
436
437 let mut events = vec![];
438 let transfer = &target_state.transfer;
439
440 let mut channel_state = match views::get_channel_by_canonical_identifier(
441 &chain_state,
442 transfer.balance_proof.canonical_identifier.clone(),
443 ) {
444 Some(channel_state) => channel_state.clone(),
445 None =>
446 return Ok(TargetTransition {
447 new_state: Some(target_state),
448 chain_state,
449 events: vec![],
450 }),
451 };
452
453 let sender = match transfer.balance_proof.sender {
454 Some(sender) => sender,
455 None => return Err("Transfer sender should be set".to_owned().into()),
456 };
457 let recipient_metadata = views::get_address_metadata(sender, transfer.route_states.clone());
458
459 let unlock_event =
460 match channel::handle_unlock(&mut channel_state, state_change, recipient_metadata) {
461 Ok(unlock_event) => unlock_event,
462 Err((_, error_event)) =>
463 return Ok(TargetTransition {
464 new_state: Some(target_state),
465 chain_state,
466 events: vec![error_event],
467 }),
468 };
469
470 update_channel(&mut chain_state, channel_state.clone()).map_err(Into::into)?;
471
472 let payment_received_success = PaymentReceivedSuccess {
473 token_network_registry_address: channel_state.token_network_registry_address,
474 token_network_address: channel_state.canonical_identifier.token_network_address,
475 identifier: transfer.payment_identifier,
476 amount: transfer.lock.amount,
477 initiator: transfer.initiator,
478 };
479 events.push(unlock_event);
480 events.push(payment_received_success.into());
481
482 Ok(TargetTransition { new_state: None, chain_state, events })
483}
484
485pub fn state_transition(
487 chain_state: ChainState,
488 target_state: Option<TargetTransferState>,
489 state_change: StateChange,
490) -> TransitionResult {
491 match state_change {
492 StateChange::ActionInitTarget(inner) =>
493 handle_init_target(chain_state, target_state, inner),
494 StateChange::Block(inner) => handle_block(chain_state, target_state, inner),
495 StateChange::ReceiveSecretReveal(inner) =>
496 handle_offchain_secret_reveal(chain_state, target_state, inner),
497 StateChange::ContractReceiveSecretReveal(inner) =>
498 handle_onchain_secret_reveal(chain_state, target_state, inner),
499 StateChange::ReceiveUnlock(inner) => handle_unlock(chain_state, target_state, inner),
500 StateChange::ReceiveLockExpired(inner) =>
501 handle_lock_expired(chain_state, target_state, inner),
502 _ => Ok(TargetTransition { new_state: target_state, chain_state, events: vec![] }),
503 }
504}