raiden_state_machine/types/
state.rs

1#![warn(clippy::missing_docs_in_private_items)]
2
3use std::{
4	cmp::max,
5	collections::HashMap,
6};
7
8use derive_more::Display;
9use itertools::izip;
10use raiden_primitives::{
11	constants::LOCKSROOT_OF_NO_LOCKS,
12	serializers::u256_to_str,
13	traits::ToBytes,
14	types::{
15		Address,
16		AddressMetadata,
17		BalanceHash,
18		BalanceProofData,
19		BlockExpiration,
20		BlockHash,
21		BlockNumber,
22		BlockTimeout,
23		Bytes,
24		CanonicalIdentifier,
25		ChainID,
26		ChannelIdentifier,
27		EncodedLock,
28		FeeAmount,
29		LockTimeout,
30		LockedAmount,
31		Locksroot,
32		MessageHash,
33		MessageIdentifier,
34		Nonce,
35		PaymentIdentifier,
36		ProportionalFeeAmount,
37		RevealTimeout,
38		Secret,
39		SecretHash,
40		SettleTimeout,
41		Signature,
42		TokenAddress,
43		TokenAmount,
44		TokenNetworkAddress,
45		TokenNetworkRegistryAddress,
46		U256,
47	},
48};
49use rug::{
50	Complete,
51	Rational,
52};
53use serde::{
54	Deserialize,
55	Serialize,
56};
57
58use super::ContractSendEvent;
59use crate::{
60	constants::{
61		DEFAULT_MEDIATION_FLAT_FEE,
62		DEFAULT_MEDIATION_PROPORTIONAL_FEE,
63		DEFAULT_MEDIATION_PROPORTIONAL_IMBALANCE_FEE,
64		DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
65		MAXIMUM_PENDING_TRANSFERS,
66	},
67	errors::StateTransitionError,
68	types::{
69		Random,
70		TransactionExecutionStatus,
71		TransactionResult,
72	},
73	views,
74};
75
76/// Determine the type of the transfer task.
77#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
78pub enum TransferRole {
79	Initiator,
80	Mediator,
81	Target,
82}
83
84/// Variants of transfer tasks.
85#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
86pub enum TransferTask {
87	Initiator(InitiatorTask),
88	Mediator(MediatorTask),
89	Target(TargetTask),
90}
91
92/// Variants of the transfer states.
93#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
94pub enum TransferState {
95	Pending,
96	Expired,
97	SecretRevealed,
98	Canceled,
99}
100
101/// Variants of the payee states.
102#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
103pub enum PayeeState {
104	Pending,
105	SecretRevealed,
106	ContractUnlock,
107	BalanceProof,
108	Expired,
109}
110
111/// Variants of the payers states.
112#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
113pub enum PayerState {
114	Pending,
115	SecretRevealed,
116	WaitingUnlock,
117	WaitingSecretReveal,
118	BalanceProof,
119	Expired,
120}
121
122/// Variants of the target states.
123#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
124pub enum TargetState {
125	Expired,
126	OffchainSecretReveal,
127	OnchainSecretReveal,
128	OnchainUnlock,
129	SecretRequest,
130}
131
132/// Variants of the waiting transfer status.
133#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
134pub enum WaitingTransferStatus {
135	Waiting,
136	Expired,
137}
138
139/// State of a transfer for the initiator node.
140#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
141pub struct InitiatorTransferState {
142	pub route: RouteState,
143	pub transfer_description: TransferDescriptionWithSecretState,
144	pub channel_identifier: ChannelIdentifier,
145	pub transfer: LockedTransferState,
146	pub received_secret_request: bool,
147	pub transfer_state: TransferState,
148}
149
150/// State of a payment for the initiator node.
151/// A single payment may have multiple transfers. E.g. because if one of the
152/// transfers fails or timeouts another transfer will be started with a
153/// different secrethash.
154#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
155pub struct InitiatorPaymentState {
156	pub routes: Vec<RouteState>,
157	pub initiator_transfers: HashMap<SecretHash, InitiatorTransferState>,
158	pub cancelled_channels: Vec<ChannelIdentifier>,
159}
160
161/// An initiator task.
162#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
163pub struct InitiatorTask {
164	pub role: TransferRole,
165	pub token_network_address: TokenNetworkAddress,
166	pub manager_state: InitiatorPaymentState,
167}
168
169/// Waiting transfer state.
170#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
171pub struct WaitingTransferState {
172	pub transfer: LockedTransferState,
173	pub status: WaitingTransferStatus,
174}
175
176/// State for a mediated transfer.
177/// A mediator will pay payee node knowing that there is a payer node to cover
178/// the token expenses. This state keeps track of transfers for
179/// the payer and payee, and the current state of the payment.
180#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
181pub struct MediationPairState {
182	pub payer_transfer: LockedTransferState,
183	pub payee_address: Address,
184	pub payee_transfer: LockedTransferState,
185	pub payer_state: PayerState,
186	pub payee_state: PayeeState,
187}
188
189/// State of a transfer for the mediator node.
190/// A mediator may manage multiple channels because of refunds, but all these
191/// channels will be used for the same transfer (not for different payments).
192#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
193pub struct MediatorTransferState {
194	pub secrethash: SecretHash,
195	pub routes: Vec<RouteState>,
196	pub refunded_channels: Vec<ChannelIdentifier>,
197	pub secret: Option<Secret>,
198	pub transfers_pair: Vec<MediationPairState>,
199	pub waiting_transfer: Option<WaitingTransferState>,
200}
201
202/// A mediator task.
203#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
204pub struct MediatorTask {
205	pub role: TransferRole,
206	pub token_network_address: TokenNetworkAddress,
207	pub mediator_state: MediatorTransferState,
208}
209/// A target task.
210#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
211pub struct TargetTask {
212	pub role: TransferRole,
213	pub token_network_address: TokenNetworkAddress,
214	pub target_state: TargetTransferState,
215}
216
217/// State of a transfer for the target node."""
218#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
219pub struct TargetTransferState {
220	pub from_hop: HopState,
221	pub transfer: LockedTransferState,
222	pub secret: Option<Secret>,
223	pub state: TargetState,
224	pub initiator_address_metadata: Option<AddressMetadata>,
225}
226
227/// Global map from secrethash to a transfer task.
228/// This mapping is used to quickly dispatch state changes by secrethash, for
229/// those that don't have a balance proof, e.g. SecretReveal.
230/// This mapping forces one task per secrethash, assuming that secrethash collision
231/// is unlikely. Features like token swaps, that span multiple networks, must
232/// be encapsulated in a single task to work with this structure.
233#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
234pub struct PaymentMappingState {
235	pub secrethashes_to_task: HashMap<SecretHash, TransferTask>,
236}
237
238/// Umbrella object that stores the per blockchain state.
239/// For each registry smart contract there must be a token network registry. Within the
240/// token network registry the existing token networks and channels are registered.
241#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
242pub struct ChainState {
243	pub chain_id: ChainID,
244	pub block_number: BlockNumber,
245	pub block_hash: BlockHash,
246	pub our_address: Address,
247	pub identifiers_to_tokennetworkregistries: HashMap<Address, TokenNetworkRegistryState>,
248	pub payment_mapping: PaymentMappingState,
249	pub pending_transactions: Vec<ContractSendEvent>,
250	pub pseudo_random_number_generator: Random,
251}
252
253impl ChainState {
254	/// Create an instance of `ChainState`.
255	pub fn new(
256		chain_id: ChainID,
257		block_number: BlockNumber,
258		block_hash: BlockHash,
259		our_address: Address,
260	) -> ChainState {
261		ChainState {
262			chain_id,
263			block_number,
264			block_hash,
265			our_address,
266			identifiers_to_tokennetworkregistries: HashMap::new(),
267			payment_mapping: PaymentMappingState { secrethashes_to_task: HashMap::new() },
268			pending_transactions: vec![],
269			pseudo_random_number_generator: Random::new(),
270		}
271	}
272}
273
274/// Corresponds to a token network registry smart contract."""
275#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
276pub struct TokenNetworkRegistryState {
277	pub address: Address,
278	pub tokennetworkaddresses_to_tokennetworks: HashMap<Address, TokenNetworkState>,
279	pub tokenaddresses_to_tokennetworkaddresses: HashMap<Address, Address>,
280}
281
282impl TokenNetworkRegistryState {
283	/// Create an instance of `TokenNetworkRegistryState`.
284	pub fn new(
285		address: Address,
286		token_network_list: Vec<TokenNetworkState>,
287	) -> TokenNetworkRegistryState {
288		let mut registry_state = TokenNetworkRegistryState {
289			address: Address::zero(),
290			tokennetworkaddresses_to_tokennetworks: HashMap::new(),
291			tokenaddresses_to_tokennetworkaddresses: HashMap::new(),
292		};
293		for token_network in token_network_list.iter() {
294			let token_network_address = token_network.address;
295			let token_address = token_network.token_address;
296			registry_state
297				.tokennetworkaddresses_to_tokennetworks
298				.insert(token_network_address, token_network.clone());
299
300			registry_state
301				.tokenaddresses_to_tokennetworkaddresses
302				.insert(token_address, token_network.address);
303		}
304		registry_state.address = address;
305		registry_state
306	}
307}
308
309/// Corresponds to a token network smart contract."""
310#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
311pub struct TokenNetworkState {
312	pub address: Address,
313	pub token_address: TokenAddress,
314	pub channelidentifiers_to_channels: HashMap<U256, ChannelState>,
315	pub partneraddresses_to_channelidentifiers: HashMap<Address, Vec<ChannelIdentifier>>,
316}
317
318impl TokenNetworkState {
319	/// Create an instance of `TokenNetworkState`.
320	pub fn new(address: Address, token_address: TokenAddress) -> TokenNetworkState {
321		TokenNetworkState {
322			address,
323			token_address,
324			channelidentifiers_to_channels: HashMap::new(),
325			partneraddresses_to_channelidentifiers: HashMap::new(),
326		}
327	}
328}
329
330/// Vairants of the channel status
331#[derive(Copy, Clone, Display, Debug, PartialEq, Eq, Serialize, Deserialize)]
332#[serde(rename_all = "lowercase")]
333pub enum ChannelStatus {
334	#[display(fmt = "opened")]
335	Opened,
336	#[display(fmt = "closing")]
337	Closing,
338	#[display(fmt = "closed")]
339	Closed,
340	#[display(fmt = "settling")]
341	Settling,
342	#[display(fmt = "settled")]
343	Settled,
344	#[display(fmt = "removed")]
345	Removed,
346	#[display(fmt = "unusable")]
347	Unusable,
348}
349
350/// Configuration parameters of the mediator fee.
351#[derive(Default, Clone, Serialize, Deserialize, Debug)]
352pub struct MediationFeeConfig {
353	pub token_to_flat_fee: HashMap<Address, FeeAmount>,
354	pub token_to_proportional_fee: HashMap<Address, ProportionalFeeAmount>,
355	pub token_to_proportional_imbalance_fee: HashMap<Address, ProportionalFeeAmount>,
356	pub cap_meditation_fees: bool,
357}
358
359impl MediationFeeConfig {
360	pub fn get_flat_fee(&self, token_address: &Address) -> FeeAmount {
361		*self
362			.token_to_flat_fee
363			.get(token_address)
364			.unwrap_or(&DEFAULT_MEDIATION_FLAT_FEE.into())
365	}
366
367	pub fn get_proportional_fee(&self, token_address: &Address) -> ProportionalFeeAmount {
368		*self
369			.token_to_proportional_fee
370			.get(token_address)
371			.unwrap_or(&DEFAULT_MEDIATION_PROPORTIONAL_FEE.into())
372	}
373
374	pub fn get_proportional_imbalance_fee(&self, token_address: &Address) -> ProportionalFeeAmount {
375		*self
376			.token_to_proportional_imbalance_fee
377			.get(token_address)
378			.unwrap_or(&DEFAULT_MEDIATION_PROPORTIONAL_IMBALANCE_FEE.into())
379	}
380}
381
382/// The state of a channel."""
383#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
384pub struct ChannelState {
385	pub canonical_identifier: CanonicalIdentifier,
386	pub token_address: TokenAddress,
387	pub token_network_registry_address: TokenNetworkRegistryAddress,
388	pub reveal_timeout: RevealTimeout,
389	pub settle_timeout: SettleTimeout,
390	pub fee_schedule: FeeScheduleState,
391	pub our_state: ChannelEndState,
392	pub partner_state: ChannelEndState,
393	pub open_transaction: TransactionExecutionStatus,
394	pub close_transaction: Option<TransactionExecutionStatus>,
395	pub settle_transaction: Option<TransactionExecutionStatus>,
396	pub update_transaction: Option<TransactionExecutionStatus>,
397}
398
399impl ChannelState {
400	/// Create an instance of `ChannelState'.`
401	#[allow(clippy::too_many_arguments)]
402	pub fn new(
403		canonical_identifier: CanonicalIdentifier,
404		token_address: TokenAddress,
405		token_network_registry_address: TokenNetworkRegistryAddress,
406		our_address: Address,
407		partner_address: Address,
408		reveal_timeout: RevealTimeout,
409		settle_timeout: SettleTimeout,
410		open_transaction: TransactionExecutionStatus,
411		fee_config: MediationFeeConfig,
412	) -> Result<ChannelState, StateTransitionError> {
413		if reveal_timeout >= settle_timeout {
414			return Err(StateTransitionError {
415				msg: format!(
416					"reveal_timeout({:?}) must be smaller than settle_timeout({:?})",
417					reveal_timeout, settle_timeout,
418				),
419			})
420		}
421
422		let our_state = ChannelEndState::new(our_address);
423
424		let partner_state = ChannelEndState::new(partner_address);
425
426		Ok(ChannelState {
427			canonical_identifier,
428			token_address,
429			token_network_registry_address,
430			reveal_timeout,
431			settle_timeout,
432			our_state,
433			partner_state,
434			open_transaction,
435			close_transaction: None,
436			settle_transaction: None,
437			update_transaction: None,
438			fee_schedule: FeeScheduleState {
439				cap_fees: fee_config.cap_meditation_fees,
440				flat: fee_config.get_flat_fee(&token_address),
441				proportional: fee_config.get_proportional_fee(&token_address),
442				imbalance_penalty: None,
443				penalty_func: None,
444			},
445		})
446	}
447
448	/// Returns the status of the channel state.
449	pub fn status(&self) -> ChannelStatus {
450		let mut status = ChannelStatus::Opened;
451
452		if let Some(settle_transaction) = &self.settle_transaction {
453			let finished_successfully =
454				settle_transaction.result == Some(TransactionResult::Success);
455			let running = settle_transaction.finished_block_number.is_none();
456
457			if finished_successfully {
458				status = ChannelStatus::Settled;
459			} else if running {
460				status = ChannelStatus::Settling;
461			} else {
462				status = ChannelStatus::Unusable;
463			}
464		} else if let Some(close_transaction) = &self.close_transaction {
465			let finished_successfully =
466				close_transaction.result == Some(TransactionResult::Success);
467			let running = close_transaction.finished_block_number.is_none();
468
469			if finished_successfully {
470				status = ChannelStatus::Closed;
471			} else if running {
472				status = ChannelStatus::Closing;
473			} else {
474				status = ChannelStatus::Unusable;
475			}
476		}
477
478		status
479	}
480
481	/// Returns total deposit amount for our side.
482	pub fn our_total_deposit(&self) -> TokenAmount {
483		self.our_state.contract_balance
484	}
485
486	/// Returns total deposit amount for partner's side.
487	pub fn partner_total_deposit(&self) -> TokenAmount {
488		self.partner_state.contract_balance
489	}
490
491	/// Returns the total withdraw amount for our side.
492	pub fn our_total_withdraw(&self) -> TokenAmount {
493		self.our_state.total_withdraw()
494	}
495
496	/// Returns the total withdraw amount for partner's side.
497	pub fn partner_total_withdraw(&self) -> TokenAmount {
498		self.partner_state.total_withdraw()
499	}
500
501	/// Returns the total capacity amount for the channel.
502	pub fn capacity(&self) -> TokenAmount {
503		self.our_state.contract_balance + self.partner_state.contract_balance -
504			self.our_state.total_withdraw() -
505			self.partner_state.total_withdraw()
506	}
507
508	/// Returns true if a channel is usable for a new transfer.
509	pub fn is_usable_for_new_transfer(
510		&self,
511		amount: TokenAmount,
512		lock_timeout: Option<LockTimeout>,
513	) -> bool {
514		let pending_transfers = self.our_state.count_pending_transfers();
515		let distributable = views::channel_distributable(&self.our_state, &self.partner_state);
516		let lock_timeout_valid = match lock_timeout {
517			Some(lock_timeout) =>
518				lock_timeout <= self.settle_timeout && lock_timeout > self.reveal_timeout,
519			None => true,
520		};
521		let is_valid_settle_timeout = self.settle_timeout >= self.reveal_timeout * 2;
522
523		if self.status() != ChannelStatus::Opened {
524			return false
525		}
526
527		if !is_valid_settle_timeout {
528			return false
529		}
530
531		if pending_transfers >= MAXIMUM_PENDING_TRANSFERS {
532			return false
533		}
534
535		if amount > distributable {
536			return false
537		}
538
539		if !self.our_state.is_valid_amount(amount) {
540			return false
541		}
542
543		if !lock_timeout_valid {
544			return false
545		}
546
547		true
548	}
549
550	/// Returns true of channel is usable to mediate a transfer.
551	pub fn is_usable_for_mediation(
552		&self,
553		transfer_amount: TokenAmount,
554		lock_timeout: BlockTimeout,
555	) -> bool {
556		self.is_usable_for_new_transfer(transfer_amount, Some(lock_timeout))
557	}
558}
559
560/// The state of one of the nodes in a two party channel.
561#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
562pub struct ChannelEndState {
563	pub address: Address,
564	pub contract_balance: TokenAmount,
565	pub onchain_total_withdraw: TokenAmount,
566	pub withdraws_pending: HashMap<U256, PendingWithdrawState>,
567	pub withdraws_expired: Vec<ExpiredWithdrawState>,
568	pub initiated_coop_settle: Option<CoopSettleState>,
569	pub expired_coop_settles: Vec<CoopSettleState>,
570	pub secrethashes_to_lockedlocks: HashMap<SecretHash, HashTimeLockState>,
571	pub secrethashes_to_unlockedlocks: HashMap<SecretHash, UnlockPartialProofState>,
572	pub secrethashes_to_onchain_unlockedlocks: HashMap<SecretHash, UnlockPartialProofState>,
573	pub balance_proof: Option<BalanceProofState>,
574	pub pending_locks: PendingLocksState,
575	pub onchain_locksroot: Locksroot,
576	pub nonce: Nonce,
577}
578
579impl ChannelEndState {
580	/// Return an instance of `ChannelEndState`.
581	pub fn new(address: Address) -> Self {
582		Self {
583			address,
584			contract_balance: TokenAmount::zero(),
585			onchain_total_withdraw: TokenAmount::zero(),
586			withdraws_pending: HashMap::new(),
587			withdraws_expired: vec![],
588			secrethashes_to_lockedlocks: HashMap::new(),
589			secrethashes_to_unlockedlocks: HashMap::new(),
590			secrethashes_to_onchain_unlockedlocks: HashMap::new(),
591			balance_proof: None,
592			pending_locks: PendingLocksState::default(),
593			onchain_locksroot: *LOCKSROOT_OF_NO_LOCKS,
594			nonce: Nonce::zero(),
595			initiated_coop_settle: None,
596			expired_coop_settles: vec![],
597		}
598	}
599
600	/// returns the off-chain total withdraw amount.
601	pub fn offchain_total_withdraw(&self) -> TokenAmount {
602		self.withdraws_pending
603			.values()
604			.map(|w| w.total_withdraw)
605			.fold(TokenAmount::zero(), max)
606	}
607
608	/// Returns the total of off-chain and on-chain withdraw amounts.
609	pub fn total_withdraw(&self) -> TokenAmount {
610		max(self.offchain_total_withdraw(), self.onchain_total_withdraw)
611	}
612
613	/// Returns the next usable nonce.
614	pub fn next_nonce(&self) -> Nonce {
615		self.nonce + 1
616	}
617
618	/// Returns the number of pending transfers.
619	pub fn count_pending_transfers(&self) -> usize {
620		self.pending_locks.locks.len()
621	}
622
623	/// Returns the total amount locked.
624	pub fn locked_amount(&self) -> TokenAmount {
625		let total_pending: TokenAmount = self
626			.secrethashes_to_lockedlocks
627			.values()
628			.map(|lock| lock.amount)
629			.fold(TokenAmount::zero(), |acc, x| acc + x);
630		let total_unclaimed: TokenAmount = self
631			.secrethashes_to_unlockedlocks
632			.values()
633			.map(|unlock| unlock.lock.amount)
634			.fold(TokenAmount::zero(), |acc, x| acc + x);
635		let total_unclaimed_onchain: TokenAmount = self
636			.secrethashes_to_onchain_unlockedlocks
637			.values()
638			.map(|unlock| unlock.lock.amount)
639			.fold(TokenAmount::zero(), |acc, x| acc + x);
640		total_pending + total_unclaimed + total_unclaimed_onchain
641	}
642
643	/// Returns the latest balance proof.
644	pub fn get_current_balanceproof(&self) -> BalanceProofData {
645		match &self.balance_proof {
646			Some(bp) => (bp.locksroot, bp.nonce, bp.transferred_amount, bp.locked_amount),
647			None =>
648				(*LOCKSROOT_OF_NO_LOCKS, Nonce::default(), TokenAmount::zero(), TokenAmount::zero()),
649		}
650	}
651
652	/// Returns true if the amount after unlock is valid
653	pub fn is_valid_amount(&self, amount: TokenAmount) -> bool {
654		let (_, _, transferred_amount, locked_amount) = self.get_current_balanceproof();
655		let transferred_amount_after_unlock =
656			transferred_amount.checked_add(locked_amount).map(|r| r.saturating_add(amount));
657		transferred_amount_after_unlock.is_some()
658	}
659
660	/// Returns true if secret is known either off-chain or on-chain.
661	pub fn is_secret_known(&self, secrethash: SecretHash) -> bool {
662		self.is_secret_known_offchain(secrethash) || self.secret_known_onchain(secrethash)
663	}
664
665	/// Returns true if secret is known on-chain.
666	pub fn secret_known_onchain(&self, secrethash: SecretHash) -> bool {
667		self.secrethashes_to_onchain_unlockedlocks.contains_key(&secrethash)
668	}
669
670	/// Returns true if secret is known off-chain.
671	pub fn is_secret_known_offchain(&self, secrethash: SecretHash) -> bool {
672		self.secrethashes_to_unlockedlocks.contains_key(&secrethash) ||
673			self.secrethashes_to_onchain_unlockedlocks.contains_key(&secrethash)
674	}
675
676	/// Returns the secret of a lock if known.
677	pub fn get_secret(&self, secrethash: SecretHash) -> Option<Secret> {
678		let mut partial_unlock_proof = self.secrethashes_to_unlockedlocks.get(&secrethash);
679		if partial_unlock_proof.is_none() {
680			partial_unlock_proof = self.secrethashes_to_onchain_unlockedlocks.get(&secrethash);
681		}
682
683		if let Some(partial_unlock_proof) = partial_unlock_proof {
684			return Some(partial_unlock_proof.secret.clone())
685		}
686
687		None
688	}
689}
690
691/// Proof of a channel balance that can be used on-chain to resolve
692/// disputes.
693#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
694pub struct BalanceProofState {
695	pub nonce: Nonce,
696	pub transferred_amount: TokenAmount,
697	pub locked_amount: LockedAmount,
698	pub locksroot: Locksroot,
699	pub canonical_identifier: CanonicalIdentifier,
700	pub balance_hash: BalanceHash,
701	pub message_hash: Option<MessageHash>,
702	pub signature: Option<Signature>,
703	pub sender: Option<Address>,
704}
705
706/// List of encoded locks.
707#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
708pub struct PendingLocksState {
709	pub locks: Vec<EncodedLock>,
710}
711
712/// Stores the lock along with its unlocking secret.
713#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
714pub struct UnlockPartialProofState {
715	pub lock: HashTimeLockState,
716	pub secret: Secret,
717	pub amount: TokenAmount,
718	pub expiration: BlockExpiration,
719	pub secrethash: SecretHash,
720	pub encoded: EncodedLock,
721}
722
723/// Represents a hash time lock.
724#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
725pub struct HashTimeLockState {
726	pub amount: TokenAmount,
727	pub expiration: BlockExpiration,
728	pub secrethash: SecretHash,
729	pub encoded: EncodedLock,
730}
731
732impl HashTimeLockState {
733	/// Creates an instance of `HashTimeLockState`.
734	pub fn create(
735		amount: TokenAmount,
736		expiration: BlockExpiration,
737		secrethash: SecretHash,
738	) -> Self {
739		let mut data = expiration.to_be_bytes();
740		data.extend_from_slice(&amount.to_bytes());
741		data.extend_from_slice(secrethash.as_bytes());
742		Self { amount, expiration, secrethash, encoded: Bytes(data) }
743	}
744}
745
746/// State of an expired withdraw.
747#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
748pub struct ExpiredWithdrawState {
749	pub total_withdraw: TokenAmount,
750	pub expiration: BlockExpiration,
751	pub nonce: Nonce,
752	pub recipient_metadata: Option<AddressMetadata>,
753}
754
755/// State of a pending withdraw.
756#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
757pub struct PendingWithdrawState {
758	pub total_withdraw: TokenAmount,
759	pub expiration: BlockExpiration,
760	pub nonce: Nonce,
761	pub recipient_metadata: Option<AddressMetadata>,
762}
763
764impl PendingWithdrawState {
765	/// Calculates the expiration threshold for a pending withdraw.
766	pub fn expiration_threshold(&self) -> BlockExpiration {
767		self.expiration
768			.saturating_add(DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS.saturating_mul(2).into())
769			.into()
770	}
771
772	/// Returns true if a pending withdraw has expired.
773	pub fn has_expired(&self, current_block: BlockNumber) -> bool {
774		let threshold = self.expiration_threshold();
775		current_block >= threshold
776	}
777}
778
779/// The state of a pending cooperative settle underway.
780#[derive(Default, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
781pub struct CoopSettleState {
782	pub total_withdraw_initiator: TokenAmount,
783	pub total_withdraw_partner: TokenAmount,
784	pub expiration: BlockExpiration,
785	pub partner_signature_request: Option<Signature>,
786	pub partner_signature_confirmation: Option<Signature>,
787	pub transaction: Option<TransactionExecutionStatus>,
788}
789
790/// Linear interpolation of a function with given points
791#[derive(Clone, Default, Debug, Eq, PartialEq)]
792pub struct Interpolate {
793	/// X points
794	pub(crate) x_list: Vec<Rational>,
795	/// Y points
796	pub(crate) y_list: Vec<Rational>,
797	/// Slopes
798	pub(crate) slopes: Vec<Rational>,
799}
800
801impl Interpolate {
802	pub fn new(x_list: Vec<Rational>, y_list: Vec<Rational>) -> Result<Self, String> {
803		for (x, y) in x_list.iter().zip(x_list[1..].iter()) {
804			let result = (y - x).complete();
805			if result <= 0 {
806				return Err("x_list must be in strictly ascending order".to_owned())
807			}
808		}
809		let intervals: Vec<_> = izip!(&x_list, &x_list[1..], &y_list, &y_list[1..]).collect();
810		let slopes = intervals
811			.into_iter()
812			.map(|(x1, x2, y1, y2)| ((y2 - y1).complete() / (x2 - x1).complete()))
813			.collect();
814
815		Ok(Self { x_list, y_list, slopes })
816	}
817
818	pub fn calculate(&self, x: Rational) -> Result<Rational, String> {
819		let last_x = self.x_list[self.x_list.len() - 1].clone();
820		let last_y = self.y_list[self.y_list.len() - 1].clone();
821		if !(self.x_list[0] <= x && x <= last_x) {
822			return Err("x out of bounds".to_owned())
823		}
824
825		if x == last_x {
826			return Ok(last_y)
827		}
828		let i = bisection::bisect_right(&self.x_list, &x) - 1;
829		Ok(self.y_list[i].clone() + (self.slopes[i].clone() * (x - self.x_list[i].clone())))
830	}
831}
832
833/// Mediation fee schedule parameters.
834#[derive(Serialize, Deserialize, Clone, Default, Debug, Eq, PartialEq)]
835pub struct FeeScheduleState {
836	pub cap_fees: bool,
837	#[serde(serialize_with = "u256_to_str")]
838	pub flat: U256,
839	#[serde(serialize_with = "u256_to_str")]
840	pub proportional: U256,
841	pub imbalance_penalty: Option<Vec<(U256, U256)>>,
842	#[serde(skip)]
843	pub penalty_func: Option<Interpolate>,
844}
845
846impl FeeScheduleState {
847	/// Updates the penalty function based on capacity updates.
848	pub fn update_penalty_func(&mut self) {
849		if let Some(imbalance_penalty) = &self.imbalance_penalty {
850			let x_list =
851				imbalance_penalty.iter().map(|(x, _)| Rational::from(x.as_u128())).collect();
852			let y_list =
853				imbalance_penalty.iter().map(|(_, y)| Rational::from(y.as_u128())).collect();
854			self.penalty_func = Interpolate::new(x_list, y_list).ok();
855		}
856	}
857
858	/// Returns the fee based on penalty function.
859	pub fn fee(&self, balance: Rational, amount: Rational) -> Result<Rational, String> {
860		let flat = Rational::from(self.flat.as_u128());
861		let proportional = Rational::from((self.proportional.as_u128(), 1000000));
862		let value = flat + (proportional * amount.clone());
863		let addition = if let Some(penalty_func) = &self.penalty_func {
864			penalty_func.calculate(balance.clone() + amount)? - penalty_func.calculate(balance)?
865		} else {
866			Rational::from(0)
867		};
868		Ok(value + addition)
869	}
870
871	/// Returns the mediation fee `Interpolate` instance.
872	#[allow(clippy::too_many_arguments)]
873	pub fn mediation_fee_func(
874		mut schedule_in: Self,
875		mut schedule_out: Self,
876		balance_in: TokenAmount,
877		balance_out: TokenAmount,
878		receivable: TokenAmount,
879		amount_with_fees: Option<TokenAmount>,
880		amount_without_fees: Option<TokenAmount>,
881		cap_fees: bool,
882	) -> Result<Interpolate, String> {
883		if amount_with_fees.is_none() && amount_without_fees.is_none() {
884			return Err(
885				"Must be called with either amount_with_fees or amount_without_fees".to_owned()
886			)
887		}
888
889		if balance_out.is_zero() && receivable.is_zero() {
890			return Err("Undefined mediation fee".to_owned())
891		}
892
893		if schedule_in.penalty_func.is_none() {
894			let total = balance_in + receivable;
895			schedule_in.penalty_func = Some(Interpolate::new(
896				vec![Rational::from(0), Rational::from(total.as_u128())],
897				vec![Rational::from(0), Rational::from(0)],
898			)?);
899		}
900		if schedule_out.penalty_func.is_none() {
901			schedule_out.penalty_func = Some(Interpolate::new(
902				vec![Rational::from(0), Rational::from(balance_out.as_u128())],
903				vec![Rational::from(0), Rational::from(0)],
904			)?)
905		}
906		let max_x = if amount_with_fees.is_none() { receivable } else { balance_out };
907		let mut x_list = Self::calculate_x_values(
908			schedule_in.penalty_func.clone().expect("penalty_func set above"),
909			schedule_out.penalty_func.clone().expect("penalty_func set above"),
910			balance_in,
911			balance_out,
912			max_x,
913		);
914
915		let mut y_list = vec![];
916		for x in x_list.iter() {
917			let add_in = if let Some(amount) = amount_with_fees {
918				Rational::from(amount.as_u128())
919			} else {
920				x.clone()
921			};
922			let add_out = if let Some(amount) = amount_without_fees {
923				-Rational::from(amount.as_u128())
924			} else {
925				(-x).complete()
926			};
927
928			let fee_in = schedule_in.fee(Rational::from(balance_in.as_u128()), add_in)?;
929			let fee_out = schedule_out.fee(Rational::from(balance_out.as_u128()), add_out)?;
930
931			let y = fee_in + fee_out;
932			y_list.push(y);
933		}
934		if cap_fees {
935			(x_list, y_list) = Self::cap_fees(x_list, y_list);
936		}
937		Interpolate::new(x_list, y_list)
938	}
939
940	/// Calculate x points.
941	fn calculate_x_values(
942		penalty_func_in: Interpolate,
943		penalty_func_out: Interpolate,
944		balance_in: TokenAmount,
945		balance_out: TokenAmount,
946		max_x: TokenAmount,
947	) -> Vec<Rational> {
948		let balance_in = Rational::from(balance_in.as_u128());
949		let balance_out = Rational::from(balance_out.as_u128());
950		let max_x = Rational::from(max_x.as_u128());
951		let all_x_values: Vec<Rational> = penalty_func_in
952			.x_list
953			.iter()
954			.map(|x| (x - balance_in.clone()))
955			.chain(penalty_func_out.x_list.iter().map(|x| balance_out.clone() - x))
956			.collect();
957		let mut all_x_values = all_x_values
958			.into_iter()
959			.map(|x| x.min(balance_out.clone()).min(max_x.clone()).max(Rational::from(0)))
960			.collect::<Vec<_>>();
961		all_x_values.sort();
962		all_x_values.dedup();
963		all_x_values
964	}
965
966	/// Set a cap on fees
967	fn cap_fees(x_list: Vec<Rational>, y_list: Vec<Rational>) -> (Vec<Rational>, Vec<Rational>) {
968		let mut x_list = x_list;
969		let mut y_list = y_list;
970		for i in 0..x_list.len() - 1 {
971			let y1 = y_list[i].clone();
972			let y2 = y_list[i + 2].clone();
973			if Self::sign(&y1) * Self::sign(&y2) == -1 {
974				let x1 = x_list[i].clone();
975				let x2 = x_list[i + 2].clone();
976				let new_x = x1.clone() + y1.clone().abs() / (y2 - y1).abs() * (x2 - x1);
977				let new_index = bisection::bisect(&x_list, &new_x);
978				x_list.insert(new_index, new_x);
979				y_list.insert(new_index, Rational::from(0));
980			}
981		}
982		let y_list = y_list.into_iter().map(|y| y.max(Rational::from(0))).collect();
983		(x_list, y_list)
984	}
985
986	/// Returns 1, -1 or 0 if x is positive, negative or zero respectively.
987	fn sign(x: &Rational) -> i8 {
988		if x == &Rational::from(0) {
989			return 0
990		}
991		if x < &Rational::from(0) {
992			return -1
993		}
994		1
995	}
996}
997
998/// Deposit transaction information.
999#[derive(Serialize, Deserialize, Clone, Debug)]
1000pub struct TransactionChannelDeposit {
1001	pub participant_address: Address,
1002	pub contract_balance: TokenAmount,
1003	pub deposit_block_number: BlockNumber,
1004}
1005
1006/// Information about the next hop.
1007#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
1008pub struct HopState {
1009	pub node_address: Address,
1010	pub channel_identifier: ChannelIdentifier,
1011}
1012
1013/// A possible route for a payment to a given target.
1014#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
1015pub struct RouteState {
1016	pub route: Vec<Address>,
1017	pub address_to_metadata: HashMap<Address, AddressMetadata>,
1018	pub swaps: HashMap<Address, Address>,
1019	pub estimated_fee: TokenAmount,
1020}
1021
1022impl RouteState {
1023	/// Returns the next hop after address.
1024	pub fn hop_after(&self, address: Address) -> Option<Address> {
1025		if let Some(index) = self.route.iter().position(|route| route == &address) {
1026			if index + 1 < self.route.len() {
1027				return Some(self.route[index + 1])
1028			}
1029		}
1030
1031		None
1032	}
1033}
1034
1035/// Describes a transfer (target, amount, and token) and contains an
1036/// additional secret that can be used with a hash-time-lock.
1037#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
1038pub struct TransferDescriptionWithSecretState {
1039	pub token_network_registry_address: TokenNetworkRegistryAddress,
1040	pub payment_identifier: PaymentIdentifier,
1041	pub amount: TokenAmount,
1042	pub token_network_address: TokenNetworkAddress,
1043	pub initiator: Address,
1044	pub target: Address,
1045	pub secret: Secret,
1046	pub secrethash: SecretHash,
1047	pub lock_timeout: Option<BlockTimeout>,
1048}
1049
1050/// A pending transfer state.
1051#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
1052pub struct LockedTransferState {
1053	pub payment_identifier: PaymentIdentifier,
1054	pub token: Address,
1055	pub lock: HashTimeLockState,
1056	pub initiator: Address,
1057	pub target: Address,
1058	pub message_identifier: MessageIdentifier,
1059	pub route_states: Vec<RouteState>,
1060	pub balance_proof: BalanceProofState,
1061	pub secret: Option<Secret>,
1062}
1063
1064/// PFS state update notification.
1065#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
1066pub struct PFSUpdate {
1067	pub canonical_identifier: CanonicalIdentifier,
1068	pub update_fee_schedule: bool,
1069}