@@ -41,12 +41,17 @@ function TransactionManager(account) {
41
41
42
42
this . _remote . on ( 'ledger_closed' , updatePendingStatus ) ;
43
43
44
- this . _remote . on ( 'disconnect' , function ( ) {
45
- self . _remote . removeListener ( 'ledger_closed' , updatePendingStatus ) ;
46
- self . _remote . once ( 'connect' , function ( ) {
44
+ function handleReconnect ( ) {
45
+ self . _handleReconnect ( function ( ) {
46
+ // Handle reconnect, account_tx procedure first, before
47
+ // hooking back into ledger_closed
47
48
self . _remote . on ( 'ledger_closed' , updatePendingStatus ) ;
48
- self . _handleReconnect ( ) ;
49
49
} ) ;
50
+ } ;
51
+
52
+ this . _remote . on ( 'disconnect' , function ( ) {
53
+ self . _remote . removeListener ( 'ledger_closed' , updatePendingStatus ) ;
54
+ self . _remote . once ( 'connect' , handleReconnect ) ;
50
55
} ) ;
51
56
52
57
// Query server for next account transaction sequence
@@ -55,6 +60,29 @@ function TransactionManager(account) {
55
60
56
61
util . inherits ( TransactionManager , EventEmitter ) ;
57
62
63
+ TransactionManager . _isNoOp = function ( transaction ) {
64
+ return ( typeof transaction === 'object' )
65
+ && ( typeof transaction . tx_json === 'object' )
66
+ && ( transaction . tx_json . TransactionType === 'AccountSet' )
67
+ && ( transaction . tx_json . Flags === 0 ) ;
68
+ } ;
69
+
70
+ TransactionManager . _isRemoteError = function ( error ) {
71
+ return ( typeof error === 'object' )
72
+ && ( error . error === 'remoteError' )
73
+ && ( typeof error . remote === 'object' ) ;
74
+ } ;
75
+
76
+ TransactionManager . _isNotFound = function ( error ) {
77
+ return TransactionManager . _isRemoteError ( error )
78
+ && / ^ ( t x n N o t F o u n d | t r a n s a c t i o n N o t F o u n d ) $ / . test ( error . remote . error ) ;
79
+ } ;
80
+
81
+ TransactionManager . _isTooBusy = function ( error ) {
82
+ return TransactionManager . _isRemoteError ( error )
83
+ && ( error . remote . error === 'tooBusy' ) ;
84
+ } ;
85
+
58
86
/**
59
87
* Normalize transactions received from account transaction stream and
60
88
* account_tx
@@ -220,6 +248,16 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
220
248
transaction . emit ( 'lost' , ledger ) ;
221
249
break ;
222
250
}
251
+
252
+ if ( transaction . finalized ) {
253
+ return ;
254
+ }
255
+
256
+ if ( ledger . ledger_index > transaction . tx_json . LastLedgerSequence ) {
257
+ // Transaction must fail
258
+ transaction . emit ( 'error' , new RippleError (
259
+ 'tejMaxLedger' , 'Transaction LastLedgerSequence exceeded' ) ) ;
260
+ }
223
261
} ) ;
224
262
} ;
225
263
@@ -297,11 +335,13 @@ TransactionManager.prototype._loadSequence = function(callback) {
297
335
* On reconnect, load account_tx in case a pending transaction succeeded while
298
336
* disconnected
299
337
*
338
+ * @param [Function] callback
300
339
* @api private
301
340
*/
302
341
303
- TransactionManager . prototype . _handleReconnect = function ( ) {
342
+ TransactionManager . prototype . _handleReconnect = function ( callback ) {
304
343
var self = this ;
344
+ var callback = ( typeof callback === 'function' ) ? callback : function ( ) { } ;
305
345
306
346
if ( ! this . _pending . length ) {
307
347
return callback ( ) ;
@@ -312,6 +352,7 @@ TransactionManager.prototype._handleReconnect = function() {
312
352
if ( self . _remote . trace ) {
313
353
log . info ( 'error requesting account_tx' , err ) ;
314
354
}
355
+ callback ( ) ;
315
356
return ;
316
357
}
317
358
@@ -320,6 +361,8 @@ TransactionManager.prototype._handleReconnect = function() {
320
361
transactions . transactions . forEach ( self . _transactionReceived , self ) ;
321
362
}
322
363
364
+ callback ( ) ;
365
+
323
366
self . _loadSequence ( function ( ) {
324
367
// Resubmit pending transactions after sequence is loaded
325
368
self . _resubmit ( ) ;
@@ -480,37 +523,30 @@ TransactionManager.prototype._request = function(tx) {
480
523
}
481
524
482
525
function transactionFailed ( message ) {
483
- switch ( message . engine_result ) {
484
- case 'tefPAST_SEQ' :
485
- self . _resubmit ( 1 , tx ) ;
486
- break ;
487
- case 'tefALREADY' :
488
- if ( tx . responses === tx . submissions ) {
489
- tx . emit ( 'error' , message ) ;
490
- } else {
491
- submitRequest . once ( 'success' , submitted ) ;
492
- }
493
- break ;
494
- default :
495
- tx . emit ( 'error' , message ) ;
526
+ if ( message . engine_result === 'tefPAST_SEQ' ) {
527
+ // Transaction may succeed after Sequence is updated
528
+ self . _resubmit ( 1 , tx ) ;
496
529
}
497
530
} ;
498
531
499
532
function transactionRetry ( message ) {
533
+ // XXX This may no longer be necessary. Instead, update sequence numbers
534
+ // after a transaction fails definitively
500
535
self . _fillSequence ( tx , function ( ) {
501
536
self . _resubmit ( 1 , tx ) ;
502
537
} ) ;
503
538
} ;
504
539
505
540
function transactionFailedLocal ( message ) {
506
- if ( ! self . _remote . local_fee ) {
507
- submissionError ( message ) ;
508
- } else if ( message . engine_result === 'telINSUF_FEE_P' ) {
509
- self . _resubmit ( 2 , tx ) ;
541
+ if ( message . engine_result === 'telINSUF_FEE_P' ) {
542
+ // Transaction may succeed after Fee is updated
543
+ self . _resubmit ( 1 , tx ) ;
510
544
}
511
545
} ;
512
546
513
547
function submissionError ( error ) {
548
+ // Either a tem-class error or generic server error such as tooBusy. This
549
+ // should be a definitive failure
514
550
if ( TransactionManager . _isTooBusy ( error ) ) {
515
551
self . _resubmit ( 1 , tx ) ;
516
552
} else {
@@ -577,7 +613,7 @@ TransactionManager.prototype._request = function(tx) {
577
613
if ( remote . trace ) {
578
614
log . info ( 'timeout:' , tx . tx_json ) ;
579
615
}
580
- self . _resubmit ( 3 , tx ) ;
616
+ self . _resubmit ( 1 , tx ) ;
581
617
}
582
618
} ;
583
619
@@ -616,29 +652,6 @@ TransactionManager.prototype._request = function(tx) {
616
652
return submitRequest ;
617
653
} ;
618
654
619
- TransactionManager . _isNoOp = function ( transaction ) {
620
- return ( typeof transaction === 'object' )
621
- && ( typeof transaction . tx_json === 'object' )
622
- && ( transaction . tx_json . TransactionType === 'AccountSet' )
623
- && ( transaction . tx_json . Flags === 0 ) ;
624
- } ;
625
-
626
- TransactionManager . _isRemoteError = function ( error ) {
627
- return ( typeof error === 'object' )
628
- && ( error . error === 'remoteError' )
629
- && ( typeof error . remote === 'object' ) ;
630
- } ;
631
-
632
- TransactionManager . _isNotFound = function ( error ) {
633
- return TransactionManager . _isRemoteError ( error )
634
- && / ^ ( t x n N o t F o u n d | t r a n s a c t i o n N o t F o u n d ) $ / . test ( error . remote . error ) ;
635
- } ;
636
-
637
- TransactionManager . _isTooBusy = function ( error ) {
638
- return TransactionManager . _isRemoteError ( error )
639
- && ( error . remote . error === 'tooBusy' ) ;
640
- } ;
641
-
642
655
/**
643
656
* Entry point for TransactionManager submission
644
657
*
0 commit comments