@@ -24,60 +24,91 @@ pub fn send_and_confirm_messages_with_spinner<T: Signers>(
24
24
messages : & [ Message ] ,
25
25
signers : & T ,
26
26
) -> Result < Vec < Option < TransactionError > > , Box < dyn error:: Error > > {
27
- let commitment = rpc_client. commitment ( ) ;
28
27
let progress_bar = new_spinner_progress_bar ( ) ;
29
- let mut send_retries = 5 ;
28
+ let mut expired_blockhash_retries = 5 ;
30
29
let send_transaction_interval = Duration :: from_millis ( 10 ) ; /* ~100 TPS */
31
30
32
- let Fees {
33
- blockhash,
34
- fee_calculator : _,
35
- mut last_valid_block_height,
36
- } = rpc_client. get_fees ( ) ?;
37
-
38
- let mut transactions = vec ! [ ] ;
39
- let mut transaction_errors = vec ! [ None ; messages. len( ) ] ;
40
- for ( i, message) in messages. iter ( ) . enumerate ( ) {
41
- let mut transaction = Transaction :: new_unsigned ( message. clone ( ) ) ;
42
- transaction. try_sign ( signers, blockhash) ?;
43
- transactions. push ( ( i, transaction) ) ;
44
- }
45
-
46
- progress_bar. set_message ( "Finding leader nodes..." ) ;
31
+ progress_bar. set_message ( "Connecting..." ) ;
47
32
let tpu_client = TpuClient :: new (
48
33
rpc_client. clone ( ) ,
49
34
websocket_url,
50
35
TpuClientConfig :: default ( ) ,
51
36
) ?;
52
- loop {
53
- // Send all transactions
37
+
38
+ let mut transactions = messages
39
+ . iter ( )
40
+ . enumerate ( )
41
+ . map ( |( i, message) | ( i, Transaction :: new_unsigned ( message. clone ( ) ) ) )
42
+ . collect :: < Vec < _ > > ( ) ;
43
+ let mut transaction_errors = vec ! [ None ; messages. len( ) ] ;
44
+ let set_message =
45
+ |confirmed_transactions, block_height : u64 , last_valid_block_height : u64 , status : & str | {
46
+ progress_bar. set_message ( & format ! (
47
+ "{:>5.1}% | {:<40}[block height {}; block hash valid for {} blocks]" ,
48
+ confirmed_transactions as f64 * 100. / messages. len( ) as f64 ,
49
+ status,
50
+ block_height,
51
+ last_valid_block_height. saturating_sub( block_height) ,
52
+ ) ) ;
53
+ } ;
54
+
55
+ let mut confirmed_transactions = 0 ;
56
+ let mut block_height = rpc_client. get_block_height ( ) ?;
57
+ while expired_blockhash_retries > 0 {
58
+ let Fees {
59
+ blockhash,
60
+ fee_calculator : _,
61
+ last_valid_block_height,
62
+ } = rpc_client. get_fees ( ) ?;
63
+
54
64
let mut pending_transactions = HashMap :: new ( ) ;
55
- let num_transactions = transactions. len ( ) ;
56
- for ( i, transaction) in transactions {
57
- if !tpu_client. send_transaction ( & transaction) {
58
- let _result = rpc_client
59
- . send_transaction_with_config (
60
- & transaction,
65
+ for ( i, mut transaction) in transactions {
66
+ transaction. try_sign ( signers, blockhash) ?;
67
+ pending_transactions. insert ( transaction. signatures [ 0 ] , ( i, transaction) ) ;
68
+ }
69
+
70
+ loop {
71
+ // Send all pending transactions
72
+ let num_transactions = pending_transactions. len ( ) ;
73
+ for ( index, ( _i, transaction) ) in pending_transactions. values ( ) . enumerate ( ) {
74
+ if !tpu_client. send_transaction ( transaction) {
75
+ let _ = rpc_client. send_transaction_with_config (
76
+ transaction,
61
77
RpcSendTransactionConfig {
62
- preflight_commitment : Some ( commitment . commitment ) ,
78
+ skip_preflight : true ,
63
79
..RpcSendTransactionConfig :: default ( )
64
80
} ,
65
- )
66
- . ok ( ) ;
81
+ ) ;
82
+ }
83
+ set_message (
84
+ confirmed_transactions,
85
+ block_height,
86
+ last_valid_block_height,
87
+ & format ! ( "Sending {}/{} transactions" , index + 1 , num_transactions, ) ,
88
+ ) ;
89
+ sleep ( send_transaction_interval) ;
67
90
}
68
- pending_transactions. insert ( transaction. signatures [ 0 ] , ( i, transaction) ) ;
69
- progress_bar. set_message ( & format ! (
70
- "[{}/{}] Transactions sent" ,
71
- pending_transactions. len( ) ,
72
- num_transactions
73
- ) ) ;
74
91
75
- sleep ( send_transaction_interval) ;
76
- }
92
+ // Wait for the next block before checking fro transaction statuses
93
+ set_message (
94
+ confirmed_transactions,
95
+ block_height,
96
+ last_valid_block_height,
97
+ & format ! ( "Waiting for next block, {} pending..." , num_transactions) ,
98
+ ) ;
77
99
78
- // Collect statuses for all the transactions, drop those that are confirmed
79
- loop {
80
- let mut block_height = 0 ;
100
+ block_height = rpc_client. get_block_height ( ) ?;
101
+ let mut new_block_height = block_height;
102
+ while block_height == new_block_height {
103
+ sleep ( Duration :: from_millis ( 200 ) ) ;
104
+ new_block_height = rpc_client. get_block_height ( ) ?;
105
+ }
106
+
107
+ if new_block_height > last_valid_block_height {
108
+ break ;
109
+ }
110
+
111
+ // Collect statuses for the transactions, drop those that are confirmed
81
112
let pending_signatures = pending_transactions. keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
82
113
for pending_signatures_chunk in
83
114
pending_signatures. chunks ( MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS )
@@ -92,74 +123,40 @@ pub fn send_and_confirm_messages_with_spinner<T: Signers>(
92
123
if * confirmation_status != TransactionConfirmationStatus :: Processed
93
124
{
94
125
if let Some ( ( i, _) ) = pending_transactions. remove ( signature) {
126
+ confirmed_transactions += 1 ;
95
127
transaction_errors[ i] = status. err ;
96
128
}
97
129
}
98
130
} else if status. confirmations . is_none ( )
99
131
|| status. confirmations . unwrap ( ) > 1
100
132
{
101
133
if let Some ( ( i, _) ) = pending_transactions. remove ( signature) {
134
+ confirmed_transactions += 1 ;
102
135
transaction_errors[ i] = status. err ;
103
136
}
104
137
}
105
138
}
106
139
}
107
140
}
108
-
109
- block_height = rpc_client. get_block_height ( ) ?;
110
- progress_bar. set_message ( & format ! (
111
- "[{}/{}] Transactions confirmed. Retrying in {} blocks" ,
112
- num_transactions - pending_transactions. len( ) ,
113
- num_transactions,
114
- last_valid_block_height. saturating_sub( block_height)
115
- ) ) ;
141
+ set_message (
142
+ confirmed_transactions,
143
+ block_height,
144
+ last_valid_block_height,
145
+ "Checking transaction status..." ,
146
+ ) ;
116
147
}
117
148
118
149
if pending_transactions. is_empty ( ) {
119
150
return Ok ( transaction_errors) ;
120
151
}
121
-
122
- if block_height > last_valid_block_height {
123
- break ;
124
- }
125
-
126
- for ( _i, transaction) in pending_transactions. values ( ) {
127
- if !tpu_client. send_transaction ( transaction) {
128
- let _result = rpc_client
129
- . send_transaction_with_config (
130
- transaction,
131
- RpcSendTransactionConfig {
132
- preflight_commitment : Some ( commitment. commitment ) ,
133
- ..RpcSendTransactionConfig :: default ( )
134
- } ,
135
- )
136
- . ok ( ) ;
137
- }
138
- }
139
-
140
- if cfg ! ( not( test) ) {
141
- // Retry twice a second
142
- sleep ( Duration :: from_millis ( 500 ) ) ;
143
- }
144
152
}
145
153
146
- if send_retries == 0 {
147
- return Err ( "Transactions failed" . into ( ) ) ;
148
- }
149
- send_retries -= 1 ;
150
-
151
- // Re-sign any failed transactions with a new blockhash and retry
152
- let Fees {
153
- blockhash,
154
- fee_calculator : _,
155
- last_valid_block_height : new_last_valid_block_height,
156
- } = rpc_client. get_fees ( ) ?;
157
-
158
- last_valid_block_height = new_last_valid_block_height;
159
- transactions = vec ! [ ] ;
160
- for ( _, ( i, mut transaction) ) in pending_transactions. into_iter ( ) {
161
- transaction. try_sign ( signers, blockhash) ?;
162
- transactions. push ( ( i, transaction) ) ;
163
- }
154
+ transactions = pending_transactions. into_iter ( ) . map ( |( _k, v) | v) . collect ( ) ;
155
+ progress_bar. println ( format ! (
156
+ "Blockhash expired. {} retries remaining" ,
157
+ expired_blockhash_retries
158
+ ) ) ;
159
+ expired_blockhash_retries -= 1 ;
164
160
}
161
+ Err ( "Max retries exceeded" . into ( ) )
165
162
}
0 commit comments