1#![warn(clippy::missing_docs_in_private_items)]
2
3use std::ops::{
4 Add,
5 Mul,
6};
7
8use raiden_primitives::{
9 constants::{
10 CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
11 LOCKSROOT_OF_NO_LOCKS,
12 },
13 hashing::hash_balance_data,
14 types::{
15 Address,
16 AddressMetadata,
17 BlockExpiration,
18 BlockHash,
19 BlockNumber,
20 CanonicalIdentifier,
21 FeeAmount,
22 MessageIdentifier,
23 PaymentIdentifier,
24 Secret,
25 SecretHash,
26 TokenAmount,
27 },
28};
29use rug::{
30 ops::Pow,
31 Float,
32 Integer,
33};
34
35use self::{
36 utils::{
37 compute_locks_with,
38 compute_locks_without,
39 compute_locksroot,
40 },
41 validators::{
42 is_lock_expired,
43 is_lock_locked,
44 is_valid_action_coop_settle,
45 is_valid_action_withdraw,
46 is_valid_lock_expired,
47 is_valid_locked_transfer,
48 is_valid_refund,
49 is_valid_unlock,
50 is_valid_withdraw_confirmation,
51 is_valid_withdraw_expired,
52 is_valid_withdraw_request,
53 },
54 views::{
55 get_amount_locked,
56 get_current_balance_proof,
57 get_lock,
58 get_max_withdraw_amount,
59 get_next_nonce,
60 get_safe_initial_expiration,
61 },
62};
63use crate::{
64 constants::{
65 CHANNEL_STATES_PRIOR_TO_CLOSE,
66 NUM_DISCRETISATION_POINTS,
67 },
68 errors::StateTransitionError,
69 types::{
70 ActionChannelClose,
71 ActionChannelCoopSettle,
72 ActionChannelSetRevealTimeout,
73 ActionChannelWithdraw,
74 BalanceProofState,
75 Block,
76 ChannelEndState,
77 ChannelState,
78 ChannelStatus,
79 ContractReceiveChannelBatchUnlock,
80 ContractReceiveChannelClosed,
81 ContractReceiveChannelDeposit,
82 ContractReceiveChannelSettled,
83 ContractReceiveChannelWithdraw,
84 ContractReceiveUpdateTransfer,
85 ContractSendChannelBatchUnlock,
86 ContractSendChannelClose,
87 ContractSendChannelCoopSettle,
88 ContractSendChannelSettle,
89 ContractSendChannelUpdateTransfer,
90 ContractSendChannelWithdraw,
91 ContractSendEventInner,
92 CoopSettleState,
93 ErrorInvalidActionCoopSettle,
94 ErrorInvalidActionSetRevealTimeout,
95 ErrorInvalidActionWithdraw,
96 ErrorInvalidReceivedLockExpired,
97 ErrorInvalidReceivedLockedTransfer,
98 ErrorInvalidReceivedTransferRefund,
99 ErrorInvalidReceivedUnlock,
100 ErrorInvalidReceivedWithdrawConfirmation,
101 ErrorInvalidReceivedWithdrawExpired,
102 ErrorInvalidReceivedWithdrawRequest,
103 Event,
104 ExpiredWithdrawState,
105 FeeScheduleState,
106 HashTimeLockState,
107 LockedTransferState,
108 MediationFeeConfig,
109 PendingLocksState,
110 PendingWithdrawState,
111 Random,
112 ReceiveLockExpired,
113 ReceiveTransferRefund,
114 ReceiveUnlock,
115 ReceiveWithdrawConfirmation,
116 ReceiveWithdrawExpired,
117 ReceiveWithdrawRequest,
118 RouteState,
119 SendLockExpired,
120 SendLockedTransfer,
121 SendMessageEventInner,
122 SendProcessed,
123 SendUnlock,
124 SendWithdrawConfirmation,
125 SendWithdrawExpired,
126 SendWithdrawRequest,
127 StateChange,
128 TransactionExecutionStatus,
129 TransactionResult,
130 UnlockPartialProofState,
131 },
132 views as global_views,
133};
134
135pub mod utils;
137pub mod validators;
139pub mod views;
141
142type TransitionResult = std::result::Result<ChannelTransition, StateTransitionError>;
144
145#[derive(Debug)]
147pub struct ChannelTransition {
148 pub new_state: Option<ChannelState>,
149 pub events: Vec<Event>,
150}
151
152fn create_send_expired_lock(
154 sender_end_state: &mut ChannelEndState,
155 locked_lock: HashTimeLockState,
156 pseudo_random_number_generator: &mut Random,
157 canonical_identifier: CanonicalIdentifier,
158 recipient: Address,
159 recipient_metadata: Option<AddressMetadata>,
160) -> Result<(Option<SendLockExpired>, Option<PendingLocksState>), String> {
161 let locked_amount = get_amount_locked(sender_end_state);
162 let balance_proof = match &sender_end_state.balance_proof {
163 Some(bp) => bp.clone(),
164 None => return Ok((None, None)),
165 };
166 let updated_locked_amount = locked_amount - locked_lock.amount;
167 let transferred_amount = balance_proof.transferred_amount;
168 let secrethash = locked_lock.secrethash;
169 let pending_locks =
170 match compute_locks_without(&mut sender_end_state.pending_locks, &locked_lock) {
171 Some(locks) => locks,
172 None => return Ok((None, None)),
173 };
174
175 let nonce = get_next_nonce(sender_end_state);
176 let locksroot = compute_locksroot(&pending_locks);
177 let balance_hash = hash_balance_data(transferred_amount, locked_amount, locksroot)?;
178 let balance_proof = BalanceProofState {
179 nonce,
180 transferred_amount,
181 locksroot,
182 balance_hash,
183 canonical_identifier: canonical_identifier.clone(),
184 locked_amount: updated_locked_amount,
185 message_hash: None,
186 signature: None,
187 sender: None,
188 };
189 let send_lock_expired = SendLockExpired {
190 inner: SendMessageEventInner {
191 recipient,
192 recipient_metadata,
193 canonical_identifier,
194 message_identifier: pseudo_random_number_generator.next(),
195 },
196 balance_proof,
197 secrethash,
198 };
199
200 Ok((Some(send_lock_expired), Some(pending_locks)))
201}
202
203fn delete_unclaimed_lock(end_state: &mut ChannelEndState, secrethash: SecretHash) {
205 if end_state.secrethashes_to_lockedlocks.contains_key(&secrethash) {
206 end_state.secrethashes_to_lockedlocks.remove(&secrethash);
207 }
208
209 if end_state.secrethashes_to_unlockedlocks.contains_key(&secrethash) {
210 end_state.secrethashes_to_unlockedlocks.remove(&secrethash);
211 }
212}
213
214fn delete_lock(end_state: &mut ChannelEndState, secrethash: SecretHash) {
216 delete_unclaimed_lock(end_state, secrethash);
217
218 if end_state.secrethashes_to_onchain_unlockedlocks.contains_key(&secrethash) {
219 end_state.secrethashes_to_onchain_unlockedlocks.remove(&secrethash);
220 }
221}
222
223pub(super) fn lock_exists_in_either_channel_side(
225 channel_state: &ChannelState,
226 secrethash: SecretHash,
227) -> bool {
228 let lock_exists = |end_state: &ChannelEndState, secrethash: SecretHash| {
229 if end_state.secrethashes_to_lockedlocks.get(&secrethash).is_some() {
230 return true
231 }
232 if end_state.secrethashes_to_unlockedlocks.get(&secrethash).is_some() {
233 return true
234 }
235 if end_state.secrethashes_to_onchain_unlockedlocks.get(&secrethash).is_some() {
236 return true
237 }
238 false
239 };
240 lock_exists(&channel_state.our_state, secrethash) ||
241 lock_exists(&channel_state.partner_state, secrethash)
242}
243
244pub(super) fn send_lock_expired(
246 mut channel_state: ChannelState,
247 locked_lock: HashTimeLockState,
248 pseudo_random_number_generator: &mut Random,
249 recipient_metadata: Option<AddressMetadata>,
250) -> Result<(ChannelState, Vec<SendLockExpired>), String> {
251 if channel_state.status() != ChannelStatus::Opened {
252 return Ok((channel_state, vec![]))
253 }
254
255 let secrethash = locked_lock.secrethash;
256 let (send_lock_expired, pending_locks) = create_send_expired_lock(
257 &mut channel_state.our_state,
258 locked_lock,
259 pseudo_random_number_generator,
260 channel_state.canonical_identifier.clone(),
261 channel_state.partner_state.address,
262 recipient_metadata,
263 )?;
264
265 let events = if let (Some(send_lock_expired), Some(pending_locks)) =
266 (send_lock_expired, pending_locks)
267 {
268 channel_state.our_state.pending_locks = pending_locks;
269 channel_state.our_state.balance_proof = Some(send_lock_expired.balance_proof.clone());
270 channel_state.our_state.nonce = send_lock_expired.balance_proof.nonce;
271
272 delete_unclaimed_lock(&mut channel_state.our_state, secrethash);
273
274 vec![send_lock_expired]
275 } else {
276 vec![]
277 };
278
279 Ok((channel_state, events))
280}
281
282fn create_unlock(
284 channel_state: &mut ChannelState,
285 message_identifier: MessageIdentifier,
286 payment_identifier: PaymentIdentifier,
287 secret: Secret,
288 lock: &HashTimeLockState,
289 block_number: BlockNumber,
290 recipient_metadata: Option<AddressMetadata>,
291) -> Result<(SendUnlock, PendingLocksState), String> {
292 if channel_state.status() != ChannelStatus::Opened {
293 return Err("Channel is not open".to_owned())
294 }
295
296 if !validators::is_lock_pending(&channel_state.our_state, lock.secrethash) {
297 return Err("Lock expired".to_owned())
298 }
299
300 let expired =
301 is_lock_expired(&channel_state.our_state, lock, block_number, lock.expiration).is_ok();
302 if expired {
303 return Err("Lock expired".to_owned())
304 }
305
306 let our_balance_proof = match &channel_state.our_state.balance_proof {
307 Some(balance_proof) => balance_proof,
308 None => return Err("No transfers exist on our state".to_owned()),
309 };
310
311 let transferred_amount = lock.amount + our_balance_proof.transferred_amount;
312 let pending_locks =
313 match compute_locks_without(&mut channel_state.our_state.pending_locks, lock) {
314 Some(pending_locks) => pending_locks,
315 None => return Err("Lock is pending, it must be in the pending locks".to_owned()),
316 };
317
318 let locksroot = compute_locksroot(&pending_locks);
319 let token_address = channel_state.token_address;
320 let recipient = channel_state.partner_state.address;
321 let locked_amount = get_amount_locked(&channel_state.our_state) - lock.amount;
322 let nonce = get_next_nonce(&channel_state.our_state);
323 channel_state.our_state.nonce = nonce;
324
325 let balance_hash = hash_balance_data(transferred_amount, locked_amount, locksroot)?;
326
327 let balance_proof = BalanceProofState {
328 nonce,
329 transferred_amount,
330 locked_amount,
331 locksroot,
332 balance_hash,
333 canonical_identifier: channel_state.canonical_identifier.clone(),
334 message_hash: None,
335 signature: None,
336 sender: None,
337 };
338
339 let unlock_lock = SendUnlock {
340 inner: SendMessageEventInner {
341 recipient,
342 recipient_metadata,
343 message_identifier,
344 canonical_identifier: channel_state.canonical_identifier.clone(),
345 },
346 payment_identifier,
347 token_address,
348 balance_proof,
349 secret,
350 secrethash: lock.secrethash,
351 };
352
353 Ok((unlock_lock, pending_locks))
354}
355
356pub(super) fn send_unlock(
358 channel_state: &mut ChannelState,
359 message_identifier: MessageIdentifier,
360 payment_identifier: PaymentIdentifier,
361 secret: Secret,
362 secrethash: SecretHash,
363 block_number: BlockNumber,
364 recipient_metadata: Option<AddressMetadata>,
365) -> Result<SendUnlock, String> {
366 let lock = match get_lock(&channel_state.our_state, secrethash) {
367 Some(lock) => lock,
368 None => return Err("Caller must ensure the lock exists".to_owned()),
369 };
370
371 let (unlock, pending_locks) = create_unlock(
372 channel_state,
373 message_identifier,
374 payment_identifier,
375 secret,
376 &lock,
377 block_number,
378 recipient_metadata,
379 )?;
380
381 channel_state.our_state.balance_proof = Some(unlock.balance_proof.clone());
382 channel_state.our_state.pending_locks = pending_locks;
383
384 delete_lock(&mut channel_state.our_state, lock.secrethash);
385
386 Ok(unlock)
387}
388
389#[allow(clippy::result_large_err)]
391pub(super) fn handle_unlock(
392 channel_state: &mut ChannelState,
393 unlock: ReceiveUnlock,
394 recipient_metadata: Option<AddressMetadata>,
395) -> Result<Event, (String, Event)> {
396 Ok(
397 match is_valid_unlock(
398 &channel_state.clone(),
399 &mut channel_state.partner_state,
400 unlock.clone(),
401 ) {
402 Ok(pending_locks) => {
403 channel_state.partner_state.balance_proof = Some(unlock.balance_proof.clone());
404 channel_state.partner_state.nonce = unlock.balance_proof.nonce;
405 channel_state.partner_state.pending_locks = pending_locks;
406
407 delete_lock(&mut channel_state.partner_state, unlock.secrethash);
408
409 SendProcessed {
410 inner: SendMessageEventInner {
411 recipient: unlock.balance_proof.sender.expect("Should exist"),
412 recipient_metadata,
413 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
414 message_identifier: unlock.message_identifier,
415 },
416 }
417 .into()
418 },
419 Err(e) =>
420 return Err((
421 e.clone(),
422 ErrorInvalidReceivedUnlock { secrethash: unlock.secrethash, reason: e }.into(),
423 )),
424 },
425 )
426}
427
428fn register_onchain_secret_endstate(
430 end_state: &mut ChannelEndState,
431 secret: Secret,
432 secrethash: SecretHash,
433 secret_reveal_block_number: BlockNumber,
434 should_delete_lock: bool,
435) {
436 let mut pending_lock = None;
437 if is_lock_locked(end_state, secrethash) {
438 pending_lock = end_state.secrethashes_to_lockedlocks.get(&secrethash).cloned();
439 }
440
441 if let Some(lock) = end_state.secrethashes_to_unlockedlocks.get_mut(&secrethash) {
442 pending_lock = Some(lock.lock.clone());
443 }
444
445 if let Some(lock) = pending_lock {
446 if lock.expiration < secret_reveal_block_number {
447 return
448 }
449
450 if should_delete_lock {
451 delete_lock(end_state, secrethash);
452 }
453
454 end_state.secrethashes_to_onchain_unlockedlocks.insert(
455 secrethash,
456 UnlockPartialProofState {
457 secret,
458 secrethash,
459 lock: lock.clone(),
460 amount: lock.amount,
461 expiration: lock.expiration,
462 encoded: lock.encoded,
463 },
464 );
465 }
466}
467
468pub(super) fn register_onchain_secret(
470 channel_state: &mut ChannelState,
471 secret: Secret,
472 secrethash: SecretHash,
473 secret_reveal_block_number: BlockNumber,
474 should_delete_lock: bool,
475) {
476 register_onchain_secret_endstate(
477 &mut channel_state.our_state,
478 secret.clone(),
479 secrethash,
480 secret_reveal_block_number,
481 should_delete_lock,
482 );
483 register_onchain_secret_endstate(
484 &mut channel_state.partner_state,
485 secret,
486 secrethash,
487 secret_reveal_block_number,
488 should_delete_lock,
489 );
490}
491
492#[allow(clippy::too_many_arguments)]
494fn create_locked_transfer(
495 channel_state: &mut ChannelState,
496 initiator: Address,
497 target: Address,
498 amount: TokenAmount,
499 expiration: BlockExpiration,
500 secret: Option<Secret>,
501 secrethash: SecretHash,
502 message_identifier: MessageIdentifier,
503 payment_identifier: PaymentIdentifier,
504 route_states: Vec<RouteState>,
505 recipient_metadata: Option<AddressMetadata>,
506) -> Result<(SendLockedTransfer, PendingLocksState), String> {
507 if amount >
508 global_views::channel_distributable(
509 &channel_state.our_state,
510 &channel_state.partner_state,
511 ) {
512 return Err("Caller must make sure there is enough balance".to_string())
513 }
514
515 if channel_state.status() != ChannelStatus::Opened {
516 return Err("Caller must make sure the channel is open".to_string())
517 }
518
519 let lock = HashTimeLockState::create(amount, expiration, secrethash);
520 let pending_locks =
521 match compute_locks_with(&channel_state.our_state.pending_locks, lock.clone()) {
522 Some(pending_locks) => pending_locks,
523 None => return Err("Caller must make sure the lock isn't used twice".to_string()),
524 };
525
526 let locksroot = compute_locksroot(&pending_locks);
527
528 let transferred_amount = if let Some(our_balance_proof) = &channel_state.our_state.balance_proof
529 {
530 our_balance_proof.transferred_amount
531 } else {
532 TokenAmount::zero()
533 };
534
535 if transferred_amount.checked_add(amount).is_none() {
536 return Err("Caller must make sure the result wont overflow".to_string())
537 }
538
539 let token = channel_state.token_address;
540 let locked_amount = get_amount_locked(&channel_state.our_state) + amount;
541 let nonce = get_next_nonce(&channel_state.our_state);
542 let balance_hash = hash_balance_data(amount, locked_amount, locksroot)?;
543 let balance_proof = BalanceProofState {
544 nonce,
545 transferred_amount,
546 locked_amount,
547 locksroot,
548 balance_hash,
549 canonical_identifier: channel_state.canonical_identifier.clone(),
550 message_hash: None,
551 signature: None,
552 sender: None,
553 };
554
555 let locked_transfer = LockedTransferState {
556 payment_identifier,
557 token,
558 lock,
559 initiator,
560 target,
561 message_identifier,
562 balance_proof,
563 secret,
564 route_states: route_states.clone(),
565 };
566
567 let recipient = channel_state.partner_state.address;
568 let recipient_metadata = match recipient_metadata {
569 Some(metadata) => Some(metadata),
570 None => global_views::get_address_metadata(recipient, route_states),
571 };
572 let locked_transfer_event = SendLockedTransfer {
573 inner: SendMessageEventInner {
574 recipient,
575 recipient_metadata,
576 canonical_identifier: channel_state.canonical_identifier.clone(),
577 message_identifier,
578 },
579 transfer: locked_transfer,
580 };
581
582 Ok((locked_transfer_event, pending_locks))
583}
584
585#[allow(clippy::too_many_arguments)]
587pub(super) fn send_locked_transfer(
588 mut channel_state: ChannelState,
589 initiator: Address,
590 target: Address,
591 amount: TokenAmount,
592 expiration: BlockExpiration,
593 secret: Option<Secret>,
594 secrethash: SecretHash,
595 message_identifier: MessageIdentifier,
596 payment_identifier: PaymentIdentifier,
597 route_states: Vec<RouteState>,
598 recipient_metadata: Option<AddressMetadata>,
599) -> Result<(ChannelState, SendLockedTransfer), String> {
600 let (locked_transfer, pending_locks) = create_locked_transfer(
601 &mut channel_state,
602 initiator,
603 target,
604 amount,
605 expiration,
606 secret,
607 secrethash,
608 message_identifier,
609 payment_identifier,
610 route_states,
611 recipient_metadata,
612 )?;
613
614 let transfer = locked_transfer.transfer.clone();
615 let lock = transfer.lock.clone();
616 channel_state.our_state.balance_proof = Some(transfer.balance_proof.clone());
617 channel_state.our_state.nonce = transfer.balance_proof.nonce;
618 channel_state.our_state.pending_locks = pending_locks;
619 channel_state
620 .our_state
621 .secrethashes_to_lockedlocks
622 .insert(lock.secrethash, lock);
623
624 Ok((channel_state, locked_transfer))
625}
626
627fn send_expired_withdraws(
629 mut channel_state: ChannelState,
630 block_number: BlockNumber,
631 pseudo_random_number_generator: &mut Random,
632) -> Vec<Event> {
633 let mut events = vec![];
634
635 let withdraws_pending = channel_state.our_state.withdraws_pending.clone();
636 for withdraw_state in withdraws_pending.values() {
637 if !withdraw_state.has_expired(block_number) {
638 continue
639 }
640
641 let nonce = channel_state.our_state.next_nonce();
642 channel_state.our_state.nonce = nonce;
643
644 channel_state.our_state.withdraws_expired.push(ExpiredWithdrawState {
645 total_withdraw: withdraw_state.total_withdraw,
646 expiration: withdraw_state.expiration,
647 nonce: withdraw_state.nonce,
648 recipient_metadata: withdraw_state.recipient_metadata.clone(),
649 });
650
651 channel_state.our_state.withdraws_pending.remove(&withdraw_state.total_withdraw);
652
653 events.push(
654 SendWithdrawExpired {
655 inner: SendMessageEventInner {
656 recipient: channel_state.partner_state.address,
657 recipient_metadata: withdraw_state.recipient_metadata.clone(),
658 canonical_identifier: channel_state.canonical_identifier.clone(),
659 message_identifier: pseudo_random_number_generator.next(),
660 },
661 participant: channel_state.our_state.address,
662 total_withdraw: withdraw_state.total_withdraw,
663 nonce: channel_state.our_state.nonce,
664 expiration: withdraw_state.expiration,
665 }
666 .into(),
667 );
668 }
669
670 events
671}
672
673pub(super) fn handle_receive_lock_expired(
675 channel_state: &mut ChannelState,
676 state_change: ReceiveLockExpired,
677 block_number: BlockNumber,
678 recipient_metadata: Option<AddressMetadata>,
679) -> TransitionResult {
680 let sender = match state_change.balance_proof.sender {
681 Some(sender) => sender,
682 None =>
683 return Err(StateTransitionError { msg: "The transfer's sender is None".to_owned() }),
684 };
685 let validate_pending_locks = is_valid_lock_expired(
686 channel_state,
687 state_change.clone(),
688 &channel_state.partner_state,
689 &channel_state.our_state,
690 block_number,
691 );
692
693 let events = match validate_pending_locks {
694 Ok(pending_locks) => {
695 let nonce = state_change.balance_proof.nonce;
696 channel_state.partner_state.balance_proof = Some(state_change.balance_proof);
697 channel_state.partner_state.nonce = nonce;
698 channel_state.partner_state.pending_locks = pending_locks;
699
700 delete_unclaimed_lock(&mut channel_state.partner_state, state_change.secrethash);
701
702 let send_processed = SendProcessed {
703 inner: SendMessageEventInner {
704 recipient: sender,
705 recipient_metadata,
706 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
707 message_identifier: state_change.message_identifier,
708 },
709 };
710 vec![send_processed.into()]
711 },
712 Err(e) => {
713 let invalid_lock_expired =
714 ErrorInvalidReceivedLockExpired { secrethash: state_change.secrethash, reason: e };
715 vec![invalid_lock_expired.into()]
716 },
717 };
718
719 Ok(ChannelTransition { new_state: Some(channel_state.clone()), events })
720}
721
722pub(super) fn handle_receive_locked_transfer(
724 channel_state: &mut ChannelState,
725 mediated_transfer: LockedTransferState,
726 recipient_metadata: Option<AddressMetadata>,
727) -> Result<Event, (String, Vec<Event>)> {
728 let sender = mediated_transfer
729 .balance_proof
730 .sender
731 .ok_or("The transfer's sender is None".to_owned())
732 .map_err(|e| (e, vec![]))?;
733
734 match is_valid_locked_transfer(
735 &mediated_transfer,
736 &channel_state.clone(),
737 &channel_state.partner_state,
738 &channel_state.our_state,
739 ) {
740 Ok(pending_locks) => {
741 channel_state.partner_state.balance_proof =
742 Some(mediated_transfer.balance_proof.clone());
743 channel_state.partner_state.nonce = mediated_transfer.balance_proof.nonce;
744 channel_state.partner_state.pending_locks = pending_locks;
745
746 let lock = mediated_transfer.lock;
747 channel_state
748 .partner_state
749 .secrethashes_to_lockedlocks
750 .insert(lock.secrethash, lock);
751
752 Ok(SendProcessed {
753 inner: SendMessageEventInner {
754 recipient: sender,
755 recipient_metadata,
756 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
757 message_identifier: mediated_transfer.message_identifier,
758 },
759 }
760 .into())
761 },
762 Err(e) => {
763 let event: Event = ErrorInvalidReceivedLockedTransfer {
764 payment_identifier: mediated_transfer.payment_identifier,
765 reason: e.clone(),
766 }
767 .into();
768 Err((e, vec![event]))
769 },
770 }
771}
772
773pub(super) fn handle_refund_transfer(
775 channel_state: &mut ChannelState,
776 received_transfer: LockedTransferState,
777 refund: ReceiveTransferRefund,
778) -> Result<Event, String> {
779 let pending_locks = is_valid_refund(
780 &channel_state.clone(),
781 refund.clone(),
782 &mut channel_state.partner_state,
783 &channel_state.our_state,
784 &received_transfer,
785 );
786 let event = match pending_locks {
787 Ok(pending_locks) => {
788 channel_state.partner_state.balance_proof = Some(refund.transfer.balance_proof.clone());
789 channel_state.partner_state.nonce = refund.transfer.balance_proof.nonce;
790 channel_state.partner_state.pending_locks = pending_locks;
791
792 let lock = refund.transfer.lock;
793 channel_state
794 .partner_state
795 .secrethashes_to_lockedlocks
796 .insert(lock.secrethash, lock);
797
798 let recipient_address = channel_state.partner_state.address;
799 let recipient_metadata = global_views::get_address_metadata(
800 recipient_address,
801 received_transfer.route_states.clone(),
802 );
803 SendProcessed {
804 inner: SendMessageEventInner {
805 recipient: recipient_address,
806 recipient_metadata,
807 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
808 message_identifier: refund.transfer.message_identifier,
809 },
810 }
811 .into()
812 },
813 Err(msg) => ErrorInvalidReceivedTransferRefund {
814 payment_identifier: received_transfer.payment_identifier,
815 reason: msg,
816 }
817 .into(),
818 };
819 Ok(event)
820}
821
822fn handle_block(
824 mut channel_state: ChannelState,
825 state_change: Block,
826 block_number: BlockNumber,
827 pseudo_random_number_generator: &mut Random,
828) -> TransitionResult {
829 let mut events = vec![];
830
831 if channel_state.status() == ChannelStatus::Opened {
832 let expired_withdraws = send_expired_withdraws(
833 channel_state.clone(),
834 block_number,
835 pseudo_random_number_generator,
836 );
837 events.extend(expired_withdraws)
838 }
839
840 if channel_state.status() == ChannelStatus::Closed {
841 let close_transaction = match channel_state.close_transaction {
842 Some(ref transaction) => transaction,
843 None =>
844 return Err(StateTransitionError {
845 msg: "Channel is Closed but close_transaction is not set".to_string(),
846 }),
847 };
848 let closed_block_number = match close_transaction.finished_block_number {
849 Some(number) => number,
850 None =>
851 return Err(StateTransitionError {
852 msg: "Channel is Closed but close_transaction block number is missing"
853 .to_string(),
854 }),
855 };
856
857 let settlement_end =
858 channel_state.settle_timeout.saturating_add(*closed_block_number).into();
859 let state_change_block_number: BlockNumber = state_change.block_number;
860 if state_change_block_number > settlement_end {
861 channel_state.settle_transaction = Some(TransactionExecutionStatus {
862 started_block_number: Some(state_change.block_number),
863 finished_block_number: None,
864 result: None,
865 });
866
867 events.push(
868 ContractSendChannelSettle {
869 inner: ContractSendEventInner {
870 triggered_by_blockhash: state_change.block_hash,
871 },
872 canonical_identifier: channel_state.canonical_identifier.clone(),
873 }
874 .into(),
875 );
876 }
877 }
878
879 Ok(ChannelTransition { new_state: Some(channel_state), events })
880}
881
882fn set_closed(mut channel_state: ChannelState, block_number: BlockNumber) -> ChannelState {
884 if channel_state.close_transaction.is_none() {
885 channel_state.close_transaction = Some(TransactionExecutionStatus {
886 started_block_number: None,
887 finished_block_number: Some(block_number),
888 result: Some(TransactionResult::Success),
889 });
890 } else if let Some(ref mut close_transaction) = channel_state.close_transaction {
891 if close_transaction.finished_block_number.is_none() {
892 close_transaction.finished_block_number = Some(block_number);
893 close_transaction.result = Some(TransactionResult::Success);
894 }
895 }
896
897 channel_state
898}
899
900fn handle_channel_closed(
902 mut channel_state: ChannelState,
903 state_change: ContractReceiveChannelClosed,
904) -> TransitionResult {
905 let mut events = vec![];
906
907 let current_channel_status = channel_state.status();
908 let just_closed = state_change.canonical_identifier == channel_state.canonical_identifier &&
909 CHANNEL_STATES_PRIOR_TO_CLOSE
910 .to_vec()
911 .iter()
912 .any(|status| status == ¤t_channel_status);
913
914 if just_closed {
915 channel_state = set_closed(channel_state.clone(), state_change.block_number);
916
917 let balance_proof = match channel_state.partner_state.balance_proof {
918 Some(ref bp) => bp,
919 None => return Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] }),
920 };
921 let call_update = state_change.transaction_from != channel_state.our_state.address &&
922 channel_state.update_transaction.is_none();
923 if call_update {
924 let expiration =
925 channel_state.settle_timeout.saturating_add(*state_change.block_number).into();
926 let update = ContractSendChannelUpdateTransfer {
927 inner: ContractSendEventInner { triggered_by_blockhash: state_change.block_hash },
928 balance_proof: balance_proof.clone(),
929 expiration,
930 };
931 channel_state.update_transaction = Some(TransactionExecutionStatus {
932 started_block_number: Some(state_change.block_number),
933 finished_block_number: None,
934 result: None,
935 });
936 events.push(update.into());
937 }
938 }
939
940 Ok(ChannelTransition { new_state: Some(channel_state), events })
941}
942
943fn set_settled(mut channel_state: ChannelState, block_number: BlockNumber) -> ChannelState {
945 if channel_state.settle_transaction.is_none() {
946 channel_state.settle_transaction = Some(TransactionExecutionStatus {
947 started_block_number: None,
948 finished_block_number: Some(block_number),
949 result: Some(TransactionResult::Success),
950 });
951 } else if let Some(ref mut settle_transaction) = channel_state.settle_transaction {
952 if settle_transaction.finished_block_number.is_none() {
953 settle_transaction.finished_block_number = Some(block_number);
954 settle_transaction.result = Some(TransactionResult::Success);
955 }
956 }
957 channel_state
958}
959
960fn set_coop_settled(end_state: &mut ChannelEndState, block_number: BlockNumber) {
962 if let Some(ref mut coop_settle) = &mut end_state.initiated_coop_settle {
963 if let Some(ref mut transaction) = &mut coop_settle.transaction {
964 if transaction.finished_block_number.is_none() {
965 transaction.finished_block_number = Some(block_number);
966 transaction.result = Some(TransactionResult::Success);
967 }
968 } else {
969 coop_settle.transaction = Some(TransactionExecutionStatus {
970 started_block_number: None,
971 finished_block_number: Some(block_number),
972 result: Some(TransactionResult::Success),
973 });
974 }
975 }
976}
977
978fn handle_channel_settled(
980 mut channel_state: ChannelState,
981 state_change: ContractReceiveChannelSettled,
982) -> TransitionResult {
983 let mut events = vec![];
984
985 if state_change.canonical_identifier == channel_state.canonical_identifier {
986 channel_state = set_settled(channel_state.clone(), state_change.block_number);
987 let our_locksroot = state_change.our_onchain_locksroot;
988 let partner_locksroot = state_change.partner_onchain_locksroot;
989 let should_clear_channel =
990 our_locksroot == *LOCKSROOT_OF_NO_LOCKS && partner_locksroot == *LOCKSROOT_OF_NO_LOCKS;
991
992 let mut is_coop_settle = false;
993 let initiator_lock_check = state_change.our_onchain_locksroot == *LOCKSROOT_OF_NO_LOCKS;
994 let partner_lock_check = state_change.partner_onchain_locksroot == *LOCKSROOT_OF_NO_LOCKS;
995 if let Some(ref mut coop_settle) = &mut channel_state.our_state.initiated_coop_settle {
996 let initiator_transfer_check =
997 coop_settle.total_withdraw_initiator == state_change.our_transferred_amount;
998 let partner_transfer_check =
999 coop_settle.total_withdraw_partner == state_change.partner_transferred_amount;
1000 let initiator_checks = initiator_transfer_check && initiator_lock_check;
1001 let partner_checks = partner_transfer_check && partner_lock_check;
1002
1003 if initiator_checks && partner_checks {
1004 set_coop_settled(&mut channel_state.our_state, state_change.block_number);
1005 is_coop_settle = true;
1006 }
1007 }
1008 if let Some(ref mut coop_settle) = &mut channel_state.partner_state.initiated_coop_settle {
1009 let initiator_transfer_check =
1010 coop_settle.total_withdraw_initiator == state_change.our_transferred_amount;
1011 let partner_transfer_check =
1012 coop_settle.total_withdraw_partner == state_change.partner_transferred_amount;
1013 let initiator_checks = initiator_transfer_check && initiator_lock_check;
1014 let partner_checks = partner_transfer_check && partner_lock_check;
1015
1016 if initiator_checks && partner_checks {
1017 set_coop_settled(&mut channel_state.partner_state, state_change.block_number);
1018 is_coop_settle = true;
1019 }
1020 }
1021
1022 if is_coop_settle {
1023 channel_state.partner_state.onchain_total_withdraw =
1024 state_change.partner_transferred_amount;
1025 channel_state.our_state.onchain_total_withdraw = state_change.our_transferred_amount;
1026 }
1027
1028 if should_clear_channel {
1029 return Ok(ChannelTransition { new_state: None, events })
1030 }
1031
1032 channel_state.our_state.onchain_locksroot = our_locksroot;
1033 channel_state.partner_state.onchain_locksroot = partner_locksroot;
1034
1035 events.push(
1036 ContractSendChannelBatchUnlock {
1037 inner: ContractSendEventInner { triggered_by_blockhash: state_change.block_hash },
1038 canonical_identifier: channel_state.canonical_identifier.clone(),
1039 sender: channel_state.partner_state.address,
1040 }
1041 .into(),
1042 );
1043 }
1044
1045 Ok(ChannelTransition { new_state: Some(channel_state), events })
1046}
1047
1048fn update_contract_balance(end_state: &mut ChannelEndState, contract_balance: TokenAmount) {
1050 if contract_balance > end_state.contract_balance {
1051 end_state.contract_balance = contract_balance;
1052 }
1053}
1054
1055fn linspace(start: Float, stop: Float, num: Float) -> Vec<Float> {
1057 let step: Float = (stop - start.clone()) / (num.clone() - 1);
1061
1062 let mut result = vec![];
1063
1064 let mut i = Integer::from(0);
1065 while i < num {
1066 result.push(start.clone() + i.clone() * step.clone());
1067 i += 1;
1068 }
1069
1070 result
1071}
1072
1073pub fn calculate_imbalance_fees(
1077 channel_capacity: TokenAmount,
1078 proportional_imbalance_fee: TokenAmount,
1079) -> Option<Vec<(TokenAmount, FeeAmount)>> {
1080 const PRECISION: u32 = 500;
1082 if proportional_imbalance_fee == TokenAmount::zero() {
1083 return None
1084 }
1085
1086 if channel_capacity == TokenAmount::zero() {
1087 return None
1088 }
1089
1090 let channel_capacity = Float::with_val(PRECISION, channel_capacity.as_u128());
1091 let proportional_imbalance_fee =
1092 Float::with_val(PRECISION, proportional_imbalance_fee.as_u128());
1093 let maximum_slope = Float::with_val(PRECISION, 0.1);
1094
1095 let max_imbalance_fee =
1096 (channel_capacity.clone() * proportional_imbalance_fee) / Float::with_val(PRECISION, 1e6);
1097
1098 let s = maximum_slope;
1100 let c = max_imbalance_fee;
1101 let o: Float = channel_capacity.clone() / 2;
1102 let b: Float = s * o.clone() / c.clone();
1103 let b = b.min(&Float::with_val(PRECISION, 10.0)); let a = c / o.clone().pow(b.clone());
1105
1106 let cap: Float = channel_capacity.clone().add(1.0);
1108 let num_base_points = cap.min(&Float::with_val(PRECISION, NUM_DISCRETISATION_POINTS));
1109 let x_values: Vec<Float> =
1110 linspace(Float::with_val(PRECISION, 0), channel_capacity, num_base_points);
1111 let y_values: Vec<TokenAmount> = x_values
1112 .iter()
1113 .map(|x| a.clone() * (x - o.clone()).pow(b.clone()))
1114 .map(|n| {
1115 TokenAmount::from(
1116 n.to_integer()
1117 .expect("Panic if Integer conversion doesn't work")
1118 .to_u128()
1119 .expect("Number too large for u128"),
1120 )
1121 })
1122 .collect();
1123 let result = x_values
1124 .into_iter()
1125 .map(|n| {
1126 TokenAmount::from(
1127 n.to_integer()
1128 .expect("POanic if Integer conversion doesn't work")
1129 .to_u128()
1130 .expect("Number too large for u128"),
1131 )
1132 })
1133 .zip(y_values)
1134 .collect();
1135 Some(result)
1136}
1137
1138fn update_fee_schedule_after_balance_change(
1141 channel_state: &mut ChannelState,
1142 fee_config: &MediationFeeConfig,
1143) {
1144 let proportional_imbalance_fee =
1145 fee_config.get_proportional_imbalance_fee(&channel_state.token_address);
1146 let imbalance_penalty =
1147 calculate_imbalance_fees(channel_state.capacity(), proportional_imbalance_fee);
1148
1149 channel_state.fee_schedule = FeeScheduleState {
1150 cap_fees: channel_state.fee_schedule.cap_fees,
1151 flat: channel_state.fee_schedule.flat,
1152 proportional: channel_state.fee_schedule.proportional,
1153 imbalance_penalty,
1154 penalty_func: None,
1155 };
1156
1157 channel_state.fee_schedule.update_penalty_func()
1158}
1159
1160fn handle_channel_deposit(
1162 mut channel_state: ChannelState,
1163 state_change: ContractReceiveChannelDeposit,
1164) -> TransitionResult {
1165 let participant_address = state_change.deposit_transaction.participant_address;
1166 let contract_balance = state_change.deposit_transaction.contract_balance;
1167
1168 if participant_address == channel_state.our_state.address {
1169 update_contract_balance(&mut channel_state.our_state, contract_balance);
1170 } else if participant_address == channel_state.partner_state.address {
1171 update_contract_balance(&mut channel_state.partner_state, contract_balance);
1172 }
1173
1174 update_fee_schedule_after_balance_change(&mut channel_state, &state_change.fee_config);
1175
1176 Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] })
1177}
1178
1179fn handle_channel_withdraw(
1181 mut channel_state: ChannelState,
1182 state_change: ContractReceiveChannelWithdraw,
1183) -> TransitionResult {
1184 if state_change.participant != channel_state.our_state.address &&
1185 state_change.participant != channel_state.partner_state.address
1186 {
1187 return Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] })
1188 }
1189
1190 let end_state: &mut ChannelEndState =
1191 if state_change.participant == channel_state.our_state.address {
1192 &mut channel_state.our_state
1193 } else {
1194 &mut channel_state.partner_state
1195 };
1196
1197 if end_state.withdraws_pending.get(&state_change.total_withdraw).is_some() {
1198 end_state.withdraws_pending.remove(&state_change.total_withdraw);
1199 }
1200 end_state.onchain_total_withdraw = state_change.total_withdraw;
1201
1202 update_fee_schedule_after_balance_change(&mut channel_state, &state_change.fee_config);
1203
1204 Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] })
1205}
1206
1207fn handle_channel_batch_unlock(
1209 mut channel_state: ChannelState,
1210 state_change: ContractReceiveChannelBatchUnlock,
1211) -> TransitionResult {
1212 if channel_state.status() == ChannelStatus::Settled {
1213 if state_change.sender == channel_state.our_state.address {
1214 channel_state.our_state.onchain_locksroot = *LOCKSROOT_OF_NO_LOCKS;
1215 } else if state_change.sender == channel_state.partner_state.address {
1216 channel_state.partner_state.onchain_locksroot = *LOCKSROOT_OF_NO_LOCKS;
1217 }
1218
1219 let no_unlocks_left_to_do = channel_state.our_state.onchain_locksroot ==
1220 *LOCKSROOT_OF_NO_LOCKS &&
1221 channel_state.partner_state.onchain_locksroot == *LOCKSROOT_OF_NO_LOCKS;
1222 if no_unlocks_left_to_do {
1223 return Ok(ChannelTransition { new_state: None, events: vec![] })
1224 }
1225 }
1226
1227 Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] })
1228}
1229
1230fn handle_channel_update_transfer(
1232 mut channel_state: ChannelState,
1233 state_change: ContractReceiveUpdateTransfer,
1234 block_number: BlockNumber,
1235) -> TransitionResult {
1236 if state_change.canonical_identifier == channel_state.canonical_identifier {
1237 channel_state.update_transaction = Some(TransactionExecutionStatus {
1238 started_block_number: None,
1239 finished_block_number: Some(block_number),
1240 result: Some(TransactionResult::Success),
1241 });
1242 }
1243
1244 Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] })
1245}
1246
1247fn register_secret_endstate(
1252 end_state: &mut ChannelEndState,
1253 secret: Secret,
1254 secrethash: SecretHash,
1255) {
1256 if is_lock_locked(end_state, secrethash) {
1257 let pending_lock = match end_state.secrethashes_to_lockedlocks.get(&secrethash) {
1258 Some(lock) => lock.clone(),
1259 None => return,
1260 };
1261
1262 end_state.secrethashes_to_lockedlocks.remove(&secrethash);
1263
1264 end_state.secrethashes_to_unlockedlocks.insert(
1265 secrethash,
1266 UnlockPartialProofState {
1267 lock: pending_lock.clone(),
1268 secret,
1269 amount: pending_lock.amount,
1270 expiration: pending_lock.expiration,
1271 secrethash,
1272 encoded: pending_lock.encoded,
1273 },
1274 );
1275 }
1276}
1277
1278pub(super) fn register_offchain_secret(
1283 channel_state: &mut ChannelState,
1284 secret: Secret,
1285 secrethash: SecretHash,
1286) {
1287 register_secret_endstate(&mut channel_state.our_state, secret.clone(), secrethash);
1288 register_secret_endstate(&mut channel_state.partner_state, secret, secrethash);
1289}
1290
1291fn send_withdraw_request(
1293 channel_state: &mut ChannelState,
1294 total_withdraw: TokenAmount,
1295 expiration: BlockExpiration,
1296 pseudo_random_number_generator: &mut Random,
1297 recipient_metadata: Option<AddressMetadata>,
1298 coop_settle: bool,
1299) -> Vec<Event> {
1300 let good_channel = CHANNEL_STATES_PRIOR_TO_CLOSE
1301 .to_vec()
1302 .iter()
1303 .any(|status| status == &channel_state.status());
1304
1305 if !good_channel {
1306 return vec![]
1307 }
1308
1309 let nonce = channel_state.our_state.next_nonce();
1310
1311 let withdraw_state =
1312 PendingWithdrawState { total_withdraw, expiration, nonce, recipient_metadata };
1313
1314 channel_state.our_state.nonce = nonce;
1315 channel_state
1316 .our_state
1317 .withdraws_pending
1318 .insert(withdraw_state.total_withdraw, withdraw_state.clone());
1319
1320 vec![SendWithdrawRequest {
1321 inner: SendMessageEventInner {
1322 recipient: channel_state.partner_state.address,
1323 recipient_metadata: withdraw_state.recipient_metadata.clone(),
1324 canonical_identifier: channel_state.canonical_identifier.clone(),
1325 message_identifier: pseudo_random_number_generator.next(),
1326 },
1327 total_withdraw: withdraw_state.total_withdraw,
1328 participant: channel_state.our_state.address,
1329 nonce: channel_state.our_state.nonce,
1330 expiration: withdraw_state.expiration,
1331 coop_settle,
1332 }
1333 .into()]
1334}
1335
1336fn events_for_close(
1338 channel_state: &mut ChannelState,
1339 block_number: BlockNumber,
1340 block_hash: BlockHash,
1341) -> Result<Vec<Event>, String> {
1342 if !CHANNEL_STATES_PRIOR_TO_CLOSE.contains(&channel_state.status()) {
1343 return Ok(vec![])
1344 }
1345
1346 channel_state.close_transaction = Some(TransactionExecutionStatus {
1347 started_block_number: Some(block_number),
1348 finished_block_number: None,
1349 result: None,
1350 });
1351
1352 if let Some(balance_proof) = &channel_state.partner_state.balance_proof {
1353 if balance_proof.signature.is_none() {
1354 return Err("Balance proof is not signed".to_owned())
1355 }
1356 }
1357
1358 let close_event = ContractSendChannelClose {
1359 inner: ContractSendEventInner { triggered_by_blockhash: block_hash },
1360 canonical_identifier: channel_state.canonical_identifier.clone(),
1361 balance_proof: channel_state.partner_state.balance_proof.clone(),
1362 };
1363
1364 Ok(vec![close_event.into()])
1365}
1366
1367fn events_for_coop_settle(
1369 channel_state: &ChannelState,
1370 coop_settle_state: &mut CoopSettleState,
1371 block_number: BlockNumber,
1372 block_hash: BlockHash,
1373) -> Vec<Event> {
1374 if let Some(partner_signature_request) = &coop_settle_state.partner_signature_request {
1375 if let Some(partner_signature_confirmation) =
1376 &coop_settle_state.partner_signature_confirmation
1377 {
1378 if coop_settle_state.expiration >= block_number - channel_state.reveal_timeout {
1379 let send_coop_settle = ContractSendChannelCoopSettle {
1380 inner: ContractSendEventInner { triggered_by_blockhash: block_hash },
1381 canonical_identifier: channel_state.canonical_identifier.clone(),
1382 our_total_withdraw: coop_settle_state.total_withdraw_initiator,
1383 partner_total_withdraw: coop_settle_state.total_withdraw_partner,
1384 expiration: coop_settle_state.expiration,
1385 signature_our_withdraw: partner_signature_confirmation.clone(),
1386 signature_partner_withdraw: partner_signature_request.clone(),
1387 };
1388
1389 coop_settle_state.transaction = Some(TransactionExecutionStatus {
1390 started_block_number: Some(block_number),
1391 finished_block_number: None,
1392 result: None,
1393 });
1394
1395 return vec![send_coop_settle.into()]
1396 }
1397 }
1398 }
1399 vec![]
1400}
1401
1402fn handle_action_close(
1404 mut channel_state: ChannelState,
1405 state_change: ActionChannelClose,
1406 block_number: BlockNumber,
1407 block_hash: BlockHash,
1408) -> TransitionResult {
1409 if channel_state.canonical_identifier != state_change.canonical_identifier {
1410 return Err("Caller must ensure the canonical IDs match".to_owned().into())
1411 }
1412
1413 let events =
1414 events_for_close(&mut channel_state, block_number, block_hash).map_err(Into::into)?;
1415
1416 Ok(ChannelTransition { new_state: Some(channel_state), events })
1417}
1418
1419fn handle_action_withdraw(
1421 mut channel_state: ChannelState,
1422 state_change: ActionChannelWithdraw,
1423 block_number: BlockNumber,
1424 pseudo_random_number_generator: &mut Random,
1425) -> TransitionResult {
1426 let mut events = vec![];
1427 match is_valid_action_withdraw(&channel_state, &state_change) {
1428 Ok(_) => {
1429 let expiration =
1430 get_safe_initial_expiration(block_number, channel_state.reveal_timeout, None);
1431
1432 events = send_withdraw_request(
1433 &mut channel_state,
1434 state_change.total_withdraw,
1435 expiration,
1436 pseudo_random_number_generator,
1437 state_change.recipient_metadata,
1438 false,
1439 );
1440 },
1441 Err(e) => {
1442 events.push(
1443 ErrorInvalidActionWithdraw {
1444 attemped_withdraw: state_change.total_withdraw,
1445 reason: e,
1446 }
1447 .into(),
1448 );
1449 },
1450 };
1451 Ok(ChannelTransition { new_state: Some(channel_state), events })
1452}
1453
1454fn handle_action_set_channel_reveal_timeout(
1456 mut channel_state: ChannelState,
1457 state_change: ActionChannelSetRevealTimeout,
1458) -> TransitionResult {
1459 let double_reveal_timeout: BlockNumber = state_change.reveal_timeout.mul(2u64);
1460 let is_valid_reveal_timeout = state_change.reveal_timeout >= 7u64.into() &&
1461 channel_state.settle_timeout >= double_reveal_timeout;
1462 if !is_valid_reveal_timeout {
1463 return Ok(ChannelTransition {
1464 new_state: Some(channel_state),
1465 events: vec![ErrorInvalidActionSetRevealTimeout {
1466 reveal_timeout: state_change.reveal_timeout,
1467 reason: "Settle timeout should be at least twice as large as reveal timeout"
1468 .to_owned(),
1469 }
1470 .into()],
1471 })
1472 }
1473
1474 channel_state.reveal_timeout = state_change.reveal_timeout;
1475 Ok(ChannelTransition { new_state: Some(channel_state), events: vec![] })
1476}
1477
1478fn handle_action_coop_settle(
1480 mut channel_state: ChannelState,
1481 state_change: ActionChannelCoopSettle,
1482 block_number: BlockNumber,
1483 pseudo_random_number_generator: &mut Random,
1484) -> TransitionResult {
1485 let our_max_total_withdraw =
1486 get_max_withdraw_amount(&channel_state.our_state, &channel_state.partner_state);
1487 let partner_max_total_withdraw =
1488 get_max_withdraw_amount(&channel_state.partner_state, &channel_state.our_state);
1489
1490 let mut events = vec![];
1491 match is_valid_action_coop_settle(&channel_state, our_max_total_withdraw) {
1492 Ok(_) => {
1493 let expiration =
1494 get_safe_initial_expiration(block_number, channel_state.reveal_timeout, None);
1495 let coop_settle = CoopSettleState {
1496 total_withdraw_initiator: our_max_total_withdraw,
1497 total_withdraw_partner: partner_max_total_withdraw,
1498 expiration,
1499 partner_signature_request: None,
1500 partner_signature_confirmation: None,
1501 transaction: None,
1502 };
1503
1504 channel_state.our_state.initiated_coop_settle = Some(coop_settle);
1505
1506 let expiration =
1507 get_safe_initial_expiration(block_number, channel_state.reveal_timeout, None);
1508
1509 let withdraw_request_events = send_withdraw_request(
1510 &mut channel_state,
1511 our_max_total_withdraw,
1512 expiration,
1513 pseudo_random_number_generator,
1514 state_change.recipient_metadata,
1515 true,
1516 );
1517 events.extend(withdraw_request_events);
1518 },
1519 Err(e) => events.push(
1520 ErrorInvalidActionCoopSettle { attempted_withdraw: our_max_total_withdraw, reason: e }
1521 .into(),
1522 ),
1523 };
1524
1525 Ok(ChannelTransition { new_state: Some(channel_state), events })
1526}
1527
1528fn handle_receive_withdraw_request(
1530 mut channel_state: ChannelState,
1531 state_change: ReceiveWithdrawRequest,
1532 block_number: BlockNumber,
1533 block_hash: BlockHash,
1534 pseudo_random_number_generator: &mut Random,
1535) -> TransitionResult {
1536 let mut events = vec![];
1537 if let Err(msg) = is_valid_withdraw_request(&channel_state, &state_change) {
1538 return Ok(ChannelTransition {
1539 new_state: Some(channel_state),
1540 events: vec![ErrorInvalidReceivedWithdrawRequest {
1541 attemped_withdraw: state_change.total_withdraw,
1542 reason: msg,
1543 }
1544 .into()],
1545 })
1546 }
1547
1548 let withdraw_state = PendingWithdrawState {
1549 total_withdraw: state_change.total_withdraw,
1550 expiration: state_change.expiration,
1551 nonce: state_change.nonce,
1552 recipient_metadata: state_change.sender_metadata.clone(),
1553 };
1554 channel_state
1555 .partner_state
1556 .withdraws_pending
1557 .insert(withdraw_state.total_withdraw, withdraw_state);
1558 channel_state.partner_state.nonce = state_change.nonce;
1559
1560 if channel_state.our_state.initiated_coop_settle.is_some() || state_change.coop_settle {
1561 let partner_max_total_withdraw =
1562 get_max_withdraw_amount(&channel_state.partner_state, &channel_state.our_state);
1563 if partner_max_total_withdraw != state_change.total_withdraw {
1564 return Ok(ChannelTransition {
1565 new_state: Some(channel_state),
1566 events: vec![ErrorInvalidReceivedWithdrawRequest {
1567 attemped_withdraw: state_change.total_withdraw,
1568 reason: format!(
1569 "Partner did not withdraw with maximum balance. Should be {}",
1570 partner_max_total_withdraw
1571 ),
1572 }
1573 .into()],
1574 })
1575 }
1576
1577 if !channel_state.partner_state.pending_locks.locks.is_empty() {
1578 return Ok(ChannelTransition {
1579 new_state: Some(channel_state),
1580 events: vec![ErrorInvalidReceivedWithdrawRequest {
1581 attemped_withdraw: state_change.total_withdraw,
1582 reason: "Partner has pending transfers".to_owned(),
1583 }
1584 .into()],
1585 })
1586 }
1587
1588 if let Some(our_initiated_coop_settle) =
1589 channel_state.our_state.initiated_coop_settle.clone().as_mut()
1590 {
1591 if our_initiated_coop_settle.expiration != state_change.expiration {
1594 return Ok(ChannelTransition {
1595 new_state: Some(channel_state),
1596 events: vec![ErrorInvalidReceivedWithdrawRequest {
1597 attemped_withdraw: state_change.total_withdraw,
1598 reason: "Partner requested withdraw while we initiated a coop-settle: \
1599 Partner's withdraw has differing expiration."
1600 .to_owned(),
1601 }
1602 .into()],
1603 })
1604 }
1605
1606 if our_initiated_coop_settle.total_withdraw_partner != state_change.total_withdraw {
1607 return Ok(ChannelTransition {
1608 new_state: Some(channel_state),
1609 events: vec![ErrorInvalidReceivedWithdrawRequest {
1610 attemped_withdraw: state_change.total_withdraw,
1611 reason: "The expected total withdraw of the partner does not match the withdraw request".to_owned(),
1612 }
1613 .into()],
1614 });
1615 }
1616 our_initiated_coop_settle.partner_signature_request =
1617 Some(state_change.signature.clone());
1618 let coop_settle_events = events_for_coop_settle(
1619 &channel_state,
1620 our_initiated_coop_settle,
1621 block_number,
1622 block_hash,
1623 );
1624 channel_state.our_state.initiated_coop_settle = Some(our_initiated_coop_settle.clone());
1625 events.extend(coop_settle_events);
1626 } else {
1627 let our_max_total_withdraw =
1628 get_max_withdraw_amount(&channel_state.our_state, &channel_state.partner_state);
1629
1630 if !channel_state.our_state.pending_locks.locks.is_empty() {
1631 return Ok(ChannelTransition {
1632 new_state: Some(channel_state),
1633 events: vec![ErrorInvalidReceivedWithdrawRequest {
1634 attemped_withdraw: state_change.total_withdraw,
1635 reason: "Partner initiated coop-settle but we have pending transfers"
1636 .to_owned(),
1637 }
1638 .into()],
1639 })
1640 }
1641
1642 let partner_initiated_coop_settle = CoopSettleState {
1643 total_withdraw_initiator: state_change.total_withdraw,
1644 total_withdraw_partner: our_max_total_withdraw,
1645 expiration: state_change.expiration,
1646 partner_signature_request: Some(state_change.signature),
1647 partner_signature_confirmation: None,
1648 transaction: None,
1649 };
1650 channel_state.partner_state.initiated_coop_settle = Some(partner_initiated_coop_settle);
1651 let send_withdraw_request_events = send_withdraw_request(
1652 &mut channel_state,
1653 our_max_total_withdraw,
1654 state_change.expiration,
1655 pseudo_random_number_generator,
1656 state_change.sender_metadata.clone(),
1657 false,
1658 );
1659 events.extend(send_withdraw_request_events);
1660 }
1661 }
1662
1663 channel_state.our_state.nonce = get_next_nonce(&channel_state.our_state);
1664 let send_withdraw = SendWithdrawConfirmation {
1665 inner: SendMessageEventInner {
1666 recipient: channel_state.partner_state.address,
1667 recipient_metadata: state_change.sender_metadata,
1668 canonical_identifier: channel_state.canonical_identifier.clone(),
1669 message_identifier: state_change.message_identifier,
1670 },
1671 participant: channel_state.partner_state.address,
1672 total_withdraw: state_change.total_withdraw,
1673 nonce: channel_state.our_state.nonce,
1674 expiration: state_change.expiration,
1675 };
1676 events.push(send_withdraw.into());
1677
1678 Ok(ChannelTransition { new_state: Some(channel_state), events })
1679}
1680
1681fn handle_receive_withdraw_confirmation(
1683 mut channel_state: ChannelState,
1684 state_change: ReceiveWithdrawConfirmation,
1685 block_number: BlockNumber,
1686 block_hash: BlockHash,
1687) -> TransitionResult {
1688 let is_valid = is_valid_withdraw_confirmation(&channel_state, &state_change);
1689
1690 let withdraw_state =
1691 channel_state.our_state.withdraws_pending.get(&state_change.total_withdraw);
1692 let mut recipient_metadata = None;
1693 if let Some(withdraw_state) = withdraw_state {
1694 recipient_metadata = withdraw_state.recipient_metadata.clone();
1695 }
1696
1697 let mut events = vec![];
1698 match is_valid {
1699 Ok(_) => {
1700 channel_state.partner_state.nonce = state_change.nonce;
1701 events.push(
1702 SendProcessed {
1703 inner: SendMessageEventInner {
1704 recipient: channel_state.partner_state.address,
1705 recipient_metadata,
1706 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
1707 message_identifier: state_change.message_identifier,
1708 },
1709 }
1710 .into(),
1711 );
1712 let partner_initiated_coop_settle = &channel_state.partner_state.initiated_coop_settle;
1713 if let Some(our_initiated_coop_settle) =
1714 channel_state.our_state.initiated_coop_settle.clone().as_mut()
1715 {
1716 if partner_initiated_coop_settle.is_some() {
1717 return Err("Only one party can initiate a coop settle".to_owned().into())
1718 }
1719
1720 our_initiated_coop_settle.partner_signature_confirmation =
1721 Some(state_change.signature);
1722
1723 let coop_settle_events = events_for_coop_settle(
1724 &channel_state,
1725 our_initiated_coop_settle,
1726 block_number,
1727 block_hash,
1728 );
1729 channel_state.our_state.initiated_coop_settle =
1730 Some(our_initiated_coop_settle.clone());
1731 events.extend(coop_settle_events);
1732 } else {
1733 if partner_initiated_coop_settle.is_none() &&
1737 state_change.expiration >= block_number - channel_state.reveal_timeout
1738 {
1739 let withdraw_onchain = ContractSendChannelWithdraw {
1740 inner: ContractSendEventInner { triggered_by_blockhash: block_hash },
1741 canonical_identifier: state_change.canonical_identifier.clone(),
1742 total_withdraw: state_change.total_withdraw,
1743 expiration: state_change.expiration,
1744 partner_signature: state_change.signature,
1745 };
1746
1747 events.push(withdraw_onchain.into());
1748 }
1749 }
1750 },
1751 Err(e) => {
1752 let invalid_withdraw = ErrorInvalidReceivedWithdrawConfirmation {
1753 attemped_withdraw: state_change.total_withdraw,
1754 reason: e,
1755 };
1756
1757 events.push(invalid_withdraw.into());
1758 },
1759 }
1760
1761 Ok(ChannelTransition { new_state: Some(channel_state), events })
1762}
1763
1764fn handle_receive_withdraw_expired(
1766 mut channel_state: ChannelState,
1767 state_change: ReceiveWithdrawExpired,
1768 block_number: BlockNumber,
1769) -> TransitionResult {
1770 let mut events = vec![];
1771
1772 let withdraw_state =
1773 match channel_state.partner_state.withdraws_pending.get(&state_change.total_withdraw) {
1774 Some(withdraw_state) => withdraw_state.clone(),
1775 None =>
1776 return Ok(ChannelTransition {
1777 new_state: Some(channel_state),
1778 events: vec![ErrorInvalidReceivedWithdrawExpired {
1779 attemped_withdraw: state_change.total_withdraw,
1780 reason: format!(
1781 "Withdraw expired of {} did not correspond to a previous withdraw request",
1782 state_change.total_withdraw
1783 ),
1784 }
1785 .into()],
1786 }),
1787 };
1788
1789 let is_valid =
1790 is_valid_withdraw_expired(&channel_state, &state_change, &withdraw_state, block_number);
1791
1792 match is_valid {
1793 Ok(_) => {
1794 channel_state
1795 .partner_state
1796 .withdraws_pending
1797 .remove(&state_change.total_withdraw);
1798 channel_state.partner_state.nonce = state_change.nonce;
1799
1800 if let Some(coop_settle) = channel_state.partner_state.initiated_coop_settle.as_ref() {
1801 if coop_settle.total_withdraw_initiator == withdraw_state.total_withdraw &&
1802 coop_settle.expiration == withdraw_state.expiration
1803 {
1804 channel_state.partner_state.initiated_coop_settle = None
1808 }
1809 }
1810
1811 events.push(
1812 SendProcessed {
1813 inner: SendMessageEventInner {
1814 recipient: channel_state.partner_state.address,
1815 recipient_metadata: withdraw_state.recipient_metadata,
1816 canonical_identifier: CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
1817 message_identifier: state_change.message_identifier,
1818 },
1819 }
1820 .into(),
1821 )
1822 },
1823 Err(e) => {
1824 events.push(
1825 ErrorInvalidReceivedWithdrawExpired {
1826 attemped_withdraw: state_change.total_withdraw,
1827 reason: e,
1828 }
1829 .into(),
1830 );
1831 },
1832 }
1833
1834 Ok(ChannelTransition { new_state: Some(channel_state), events })
1835}
1836
1837fn sanity_check(transition: ChannelTransition) -> TransitionResult {
1841 let channel_state = match transition.new_state {
1842 Some(ref channel_state) => channel_state,
1843 None => return Ok(transition),
1844 };
1845 let partner_state = &channel_state.partner_state;
1846 let our_state = &channel_state.our_state;
1847
1848 let mut previous = TokenAmount::zero();
1849 let coop_settle =
1850 our_state.initiated_coop_settle.is_some() || partner_state.initiated_coop_settle.is_some();
1851
1852 for (total_withdraw, withdraw_state) in our_state.withdraws_pending.iter() {
1853 if !coop_settle {
1854 if withdraw_state.total_withdraw <= previous {
1855 return Err("Total withdraws must be ordered".to_owned().into())
1856 }
1857
1858 if total_withdraw != &withdraw_state.total_withdraw {
1859 return Err("Total withdraw mismatch".to_owned().into())
1860 }
1861
1862 previous = withdraw_state.total_withdraw;
1863 }
1864 }
1865
1866 let our_balance = global_views::channel_balance(our_state, partner_state);
1867 let partner_balance = global_views::channel_balance(partner_state, our_state);
1868
1869 let channel_capacity = channel_state.capacity();
1870 if our_balance + partner_balance != channel_capacity {
1871 return Err("The whole deposit of the channel has to be accounted for.".to_owned().into())
1872 }
1873
1874 let our_locked = get_amount_locked(our_state);
1875 let partner_locked = get_amount_locked(partner_state);
1876
1877 let (our_bp_locksroot, _, _, our_bp_locked_amount) = get_current_balance_proof(our_state);
1878 let (partner_bp_locksroot, _, _, partner_bp_locked_amount) =
1879 get_current_balance_proof(partner_state);
1880
1881 let message = "The sum of the lock's amounts, and the value of the balance proof \
1882 locked_amount must be equal, otherwise settle will not reserve the \
1883 proper amount of tokens."
1884 .to_owned();
1885
1886 if partner_locked != partner_bp_locked_amount {
1887 return Err(message.into())
1888 }
1889 if our_locked != our_bp_locked_amount {
1890 return Err(message.into())
1891 }
1892
1893 let our_distributable = global_views::channel_distributable(our_state, partner_state);
1894 let partner_distributable = global_views::channel_distributable(partner_state, our_state);
1895
1896 if our_distributable + our_locked > our_balance {
1900 return Err("Distributable + locked must not exceed balance (own)".to_owned().into())
1901 }
1902 if partner_distributable + partner_locked > partner_balance {
1903 return Err("Distributable + locked must not exceed balance (partner)".to_owned().into())
1904 }
1905
1906 let our_locksroot = compute_locksroot(&our_state.pending_locks);
1907 let partner_locksroot = compute_locksroot(&partner_state.pending_locks);
1908
1909 let message = "The balance proof locks root must match the existing locks. \
1910 Otherwise it is not possible to prove on-chain that a given lock was pending."
1911 .to_owned();
1912 if our_locksroot != our_bp_locksroot {
1913 return Err(message.into())
1914 }
1915 if partner_locksroot != partner_bp_locksroot {
1916 return Err(message.into())
1917 }
1918
1919 let message =
1920 "The lock mappings and the pending locks must be synchronised. Otherwise there is a bug."
1921 .to_owned();
1922 for lock in partner_state.secrethashes_to_lockedlocks.values() {
1923 if !partner_state.pending_locks.locks.contains(&lock.encoded) {
1924 return Err(message.into())
1925 }
1926 }
1927 for lock in partner_state.secrethashes_to_unlockedlocks.values() {
1928 if !partner_state.pending_locks.locks.contains(&lock.encoded) {
1929 return Err(message.into())
1930 }
1931 }
1932 for lock in partner_state.secrethashes_to_onchain_unlockedlocks.values() {
1933 if !partner_state.pending_locks.locks.contains(&lock.encoded) {
1934 return Err(message.into())
1935 }
1936 }
1937 for lock in our_state.secrethashes_to_lockedlocks.values() {
1938 if !our_state.pending_locks.locks.contains(&lock.encoded) {
1939 return Err(message.into())
1940 }
1941 }
1942 for lock in our_state.secrethashes_to_unlockedlocks.values() {
1943 if !our_state.pending_locks.locks.contains(&lock.encoded) {
1944 return Err(message.into())
1945 }
1946 }
1947 for lock in our_state.secrethashes_to_onchain_unlockedlocks.values() {
1948 if !our_state.pending_locks.locks.contains(&lock.encoded) {
1949 return Err(message.into())
1950 }
1951 }
1952
1953 Ok(transition)
1954}
1955
1956pub fn state_transition(
1958 channel_state: ChannelState,
1959 state_change: StateChange,
1960 block_number: BlockNumber,
1961 block_hash: BlockHash,
1962 pseudo_random_number_generator: &mut Random,
1963) -> TransitionResult {
1964 let transition = match state_change {
1965 StateChange::ActionChannelClose(inner) =>
1966 handle_action_close(channel_state, inner, block_number, block_hash),
1967 StateChange::ActionChannelWithdraw(inner) => handle_action_withdraw(
1968 channel_state,
1969 inner,
1970 block_number,
1971 pseudo_random_number_generator,
1972 ),
1973 StateChange::ActionChannelCoopSettle(inner) => handle_action_coop_settle(
1974 channel_state,
1975 inner,
1976 block_number,
1977 pseudo_random_number_generator,
1978 ),
1979 StateChange::ActionChannelSetRevealTimeout(inner) =>
1980 handle_action_set_channel_reveal_timeout(channel_state, inner),
1981 StateChange::Block(inner) =>
1982 handle_block(channel_state, inner, block_number, pseudo_random_number_generator),
1983 StateChange::ContractReceiveChannelClosed(inner) =>
1984 handle_channel_closed(channel_state, inner),
1985 StateChange::ContractReceiveChannelSettled(inner) =>
1986 handle_channel_settled(channel_state, inner),
1987 StateChange::ContractReceiveChannelDeposit(inner) =>
1988 handle_channel_deposit(channel_state, inner),
1989 StateChange::ContractReceiveChannelWithdraw(inner) =>
1990 handle_channel_withdraw(channel_state, inner),
1991 StateChange::ContractReceiveChannelBatchUnlock(inner) =>
1992 handle_channel_batch_unlock(channel_state, inner),
1993 StateChange::ContractReceiveUpdateTransfer(inner) =>
1994 handle_channel_update_transfer(channel_state, inner, block_number),
1995 StateChange::ReceiveWithdrawRequest(inner) => handle_receive_withdraw_request(
1996 channel_state,
1997 inner,
1998 block_number,
1999 block_hash,
2000 pseudo_random_number_generator,
2001 ),
2002 StateChange::ReceiveWithdrawConfirmation(inner) =>
2003 handle_receive_withdraw_confirmation(channel_state, inner, block_number, block_hash),
2004 StateChange::ReceiveWithdrawExpired(inner) =>
2005 handle_receive_withdraw_expired(channel_state, inner, block_number),
2006 _ => Err(StateTransitionError { msg: String::from("Could not transition channel") }),
2007 }?;
2008
2009 sanity_check(transition)
2010}