11import { from , merge , Observable , of } from 'rxjs' ;
2- import { exhaustMap , filter , withLatestFrom , mergeMap } from 'rxjs/operators' ;
2+ import { exhaustMap , filter , mergeMap , pluck , withLatestFrom } from 'rxjs/operators' ;
33
44import { RaidenAction } from '../../actions' ;
55import { newBlock } from '../../channels/actions' ;
6- import { RaidenConfig } from '../../config' ;
76import { RaidenState } from '../../state' ;
87import { RaidenEpicDeps } from '../../types' ;
9- import { isActionOf , isResponseOf } from '../../utils/actions' ;
8+ import { isResponseOf } from '../../utils/actions' ;
109import { RaidenError , ErrorCodes } from '../../utils/error' ;
11- import { Hash } from '../../utils/types' ;
1210import { transfer , transferExpire } from '../actions' ;
13- import { Direction , TransferState } from '../state' ;
11+ import { Direction } from '../state' ;
1412import { dispatchAndWait$ } from './utils' ;
1513
1614/**
17- * Predicate to check if a transfer has expired.
18- *
19- * For a transfer to expire it has to satisfy these conditions:
20- *
21- * - It must *not* have been unlocked.
22- * - It must *not* have been expired before.
23- * - The corresponding secret must not have been registered on-chain before the
24- * lock's expiration.
25- * - The channel must *not* be closed.
26- *
27- * @param transfer - TransferState to be checked
28- * @param confirmationBlocks - Confirmation blocks config param
29- * @param blockNumber - The current block number
30- * @returns boolean if the transfer has expired
31- */
32- function isTransferExpired (
33- transfer : TransferState ,
34- confirmationBlocks : number ,
35- blockNumber : number ,
36- ) : boolean {
37- return (
38- ! transfer . unlock &&
39- ! transfer . lockExpired &&
40- ! transfer . channelClosed &&
41- transfer . transfer . lock . expiration . add ( confirmationBlocks ) . lte ( blockNumber ) &&
42- // don't expire if secret got registered before lock expired
43- ! transfer . secret ?. registerBlock
44- ) ;
45- }
46-
47- /**
48- * Contains the core logic of {@link transferAutoExpireEpic}.
49- *
50- * @param action$ - Observable of {@link RaidenAction} actions
51- * @param state - Contains The current state of the app
52- * @param config - Contains the current app config
53- * @param config.confirmationBlocks - Confirmation blocks config param
54- * @param blockNumber - The current block number
55- * @returns Observable of {@link transferExpire.request} or {@link transfer.failure} actions
56- */
57- function autoExpire$ (
58- action$ : Observable < RaidenAction > ,
59- state : RaidenState ,
60- { confirmationBlocks } : RaidenConfig ,
61- blockNumber : number ,
62- ) : Observable < transferExpire . request | transfer . failure > {
63- // we can send LockExpired only for SENT transfers
64- return from ( Object . entries ( state . sent ) as Array < [ Hash , typeof state . sent [ string ] ] > ) . pipe (
65- filter ( ( [ , sent ] ) => isTransferExpired ( sent , confirmationBlocks , blockNumber ) ) ,
66- mergeMap ( ( [ secrethash , sent ] ) => {
67- const meta = { secrethash, direction : Direction . SENT } ;
68- // this observable acts like a Promise: emits request once, completes on success/failure
69- return merge (
70- dispatchAndWait$ (
71- action$ ,
72- transferExpire . request ( undefined , meta ) ,
73- isResponseOf ( transferExpire , meta ) ,
74- ) ,
75- // notify users that this transfer failed definitely
76- of (
77- transfer . failure (
78- new RaidenError ( ErrorCodes . XFER_EXPIRED , {
79- block : sent . transfer . lock . expiration . toString ( ) ,
80- } ) ,
81- meta ,
82- ) ,
83- ) ,
84- ) ;
85- } ) ,
86- ) ;
87- }
88-
89- /**
90- * Process newBlocks, emits transferExpire.request (request to compose&sign LockExpired for a transfer)
91- * if pending transfer's lock expired and transfer didn't unlock (succeed) in time
15+ * Process newBlocks, emits transferExpire.request (request to compose&sign LockExpired for a
16+ * transfer) if pending transfer's lock expired and transfer didn't unlock (succeed) in time
9217 * Also, emits transfer.failure, to notify users that a transfer has failed (although it'll only be
9318 * considered as completed with fail once the transferExpireProcessed arrives).
9419 *
@@ -104,15 +29,47 @@ export const transferAutoExpireEpic = (
10429 { config$ } : RaidenEpicDeps ,
10530) : Observable < transferExpire . request | transfer . failure > =>
10631 action$ . pipe (
107- filter ( isActionOf ( newBlock ) ) ,
32+ filter ( newBlock . is ) ,
33+ pluck ( 'payload' , 'blockNumber' ) ,
10834 withLatestFrom ( state$ , config$ ) ,
10935 // With interactive signing sending a lock expired message requires user
11036 // intervention. In that case it is possible for a new block to arrive
11137 // while waiting for the user permission, without the `exhaustMap` below
11238 // multiple signing requests would be emited *for the same lock*.
11339 // `exhaustMap` prevents that from happening, by blocking new signing
11440 // requests until the existing ones have been concluded.
115- exhaustMap ( ( [ { payload : { blockNumber } } , state , config ] ) =>
116- autoExpire$ ( action$ , state , config , blockNumber ) ,
41+ exhaustMap ( ( [ blockNumber , { transfers } , { confirmationBlocks } ] ) =>
42+ from (
43+ Object . values ( transfers ) . filter (
44+ ( r ) =>
45+ r . direction === Direction . SENT &&
46+ ! r . unlock &&
47+ ! r . expired &&
48+ ! r . secretRegistered &&
49+ ! r . channelClosed &&
50+ r . expiration <= blockNumber - confirmationBlocks * 2 ,
51+ ) ,
52+ ) . pipe (
53+ mergeMap ( ( doc ) => {
54+ const meta = { secrethash : doc . transfer . lock . secrethash , direction : Direction . SENT } ;
55+ // this observable acts like a Promise: emits request once, completes on success/failure
56+ return merge (
57+ dispatchAndWait$ (
58+ action$ ,
59+ transferExpire . request ( undefined , meta ) ,
60+ isResponseOf ( transferExpire , meta ) ,
61+ ) ,
62+ // notify users that this transfer failed definitely
63+ of (
64+ transfer . failure (
65+ new RaidenError ( ErrorCodes . XFER_EXPIRED , {
66+ block : doc . transfer . lock . expiration . toString ( ) ,
67+ } ) ,
68+ meta ,
69+ ) ,
70+ ) ,
71+ ) ;
72+ } ) ,
73+ ) ,
11774 ) ,
11875 ) ;
0 commit comments