raiden_state_machine/machine/channel/
mod.rs

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
135/// Channel utilities.
136pub mod utils;
137/// Channel validators.
138pub mod validators;
139/// Channel views.
140pub mod views;
141
142/// A transition result for the channel state.
143type TransitionResult = std::result::Result<ChannelTransition, StateTransitionError>;
144
145/// Channel transition content.
146#[derive(Debug)]
147pub struct ChannelTransition {
148	pub new_state: Option<ChannelState>,
149	pub events: Vec<Event>,
150}
151
152/// Create lock expired events.
153fn 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
203/// Delete locks which are still unlocked.
204fn 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
214/// Delete lock with provided secret hash.
215fn 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
223/// Check if the lock with `secrethash` exists in either our state or the partner's state"""
224pub(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
244/// Send lock expired events
245pub(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
282/// Create unlock events.
283fn 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
356/// Create and send unlock events.
357pub(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/// Handle a received unlock.
390#[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
428/// Update channel states with secret registered onchain.
429fn 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
468/// Update channel states with secret registered onchain.
469pub(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/// Create a locked transfer event.
493#[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/// Create and send a locked transfer.
586#[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
627/// Send lock expired withdraw event.
628fn 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
673/// Handle an expired lock.
674pub(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
722/// Handle a received locked transfer.
723pub(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
773/// Handle a received refund transfer.
774pub(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
822/// Handle a new block state change.
823fn 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
882/// Set channel state to closed.
883fn 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
900/// Handle channel closed onchain.
901fn 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 == &current_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
943/// Set channel state to settled.
944fn 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
960/// Set channel state to settled via cooperative settle.
961fn 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
978/// Handle an onchain channel settled event.
979fn 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
1048/// Update balance based on on-chain events.
1049fn 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
1055/// Returns a list of numbers from start to stop (inclusive).
1056fn linspace(start: Float, stop: Float, num: Float) -> Vec<Float> {
1057	// assert num > 1, "Must generate at least one step"
1058	// assert start <= stop, "start must be smaller than stop"
1059
1060	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
1073/// Calculates a U-shaped imbalance curve
1074/// The penalty term takes the following value at the extrema:
1075/// channel_capacity * (proportional_imbalance_fee / 1_000_000)
1076pub fn calculate_imbalance_fees(
1077	channel_capacity: TokenAmount,
1078	proportional_imbalance_fee: TokenAmount,
1079) -> Option<Vec<(TokenAmount, FeeAmount)>> {
1080	/// Floating point precision
1081	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	// calculate function parameters
1099	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)); // limit exponent to keep numerical stability;
1104	let a = c / o.clone().pow(b.clone());
1105
1106	// calculate discrete function points
1107	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
1138/// Update the channel state's fee schedule if balances changes
1139/// based on deposits or transfers
1140fn 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
1160/// Handle `ContractReceiveChannelDeposit` state change.
1161fn 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
1179/// Handle `ContractReceiveChannelWithdraw` state change.
1180fn 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
1207/// Handle `ContractReceiveChannelBatchUnlock` state change.
1208fn 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
1230/// Handle `ContractReceiveUpdateTransfer` state change.
1231fn 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
1247/// This will register the secret and set the lock to the unlocked stated.
1248///
1249/// Even though the lock is unlock it is *not* claimed. The capacity will
1250/// increase once the next balance proof is received.
1251fn 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
1278/// This will register the secret and set the lock to the unlocked stated.
1279///
1280/// Even though the lock is unlock it is *not* claimed. The capacity will
1281/// increase once the next balance proof is received.
1282pub(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
1291/// Returns a withdraw request event
1292fn 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
1336/// Returns events to close a channel
1337fn 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
1367/// Returns events for cooperatively settling a channel.
1368fn 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
1402/// Handle `ActionChannelClose` state change.
1403fn 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
1419/// Handle `ActionChannelWithdraw` state change.
1420fn 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
1454/// Handle `ActionChannelSetRevealTimeout` state change.
1455fn 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
1478/// Handle `ActionChannelCoopSettle` state change.
1479fn 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
1528/// Handle `ReceiveWithdrawRequest` state change.
1529fn 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			// There is a coop-settle inplace that we initiated
1592			// and partner is communicating their total withdraw with us
1593			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
1681/// Handle `ReceiveWithdrawConfirmation` state change.
1682fn 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				// Normal withdraw
1734				// Only send the transaction on-chain if there is enough time for the
1735				// withdraw transaction to be mined
1736				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
1764/// Handle `ReceiveWithdrawExpired` state change.
1765fn 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					// We declare the partner's initated coop-settle as expired
1805					// and remove it from the state.
1806					// This will be used in the handling of incoming withdraw messages.
1807					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
1837/// Some of the checks below are tautologies for the current version of the
1838/// codebase. However they are kept in there to check the constraints if/when
1839/// the code changes.
1840fn 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	// Because of overflow checks, it is possible for the distributable amount
1897	// to be lower than the available balance, therefore the sanity check has to
1898	// be lower-than instead of equal-to
1899	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
1956/// State machine for the channel state machine.
1957pub 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}