@@ -3,6 +3,12 @@ use crate::utils::wait_until;
3
3
use crate :: { Net , Node , Spec } ;
4
4
use ckb_jsonrpc_types:: Status ;
5
5
use ckb_network:: SupportProtocols ;
6
+ use ckb_types:: core:: { capacity_bytes, Capacity , TransactionBuilder , TransactionView } ;
7
+ use ckb_types:: packed:: CellOutputBuilder ;
8
+ use ckb_types:: {
9
+ packed:: { CellInput , OutPoint } ,
10
+ prelude:: * ,
11
+ } ;
6
12
7
13
const ALWAYS_SUCCESS_SCRIPT_CYCLE : u64 = 537 ;
8
14
// always_failure, as the name implies, so it doesn't matter what the cycles are
@@ -97,3 +103,202 @@ impl Spec for OrphanTxRejected {
97
103
assert ! ( matches!( ret. tx_status. status, Status :: Rejected ) ) ;
98
104
}
99
105
}
106
+
107
+ // construct a tx chain with such structure:
108
+ //
109
+ // parent
110
+ // |
111
+ // tx1
112
+ // / | \
113
+ // tx11 tx12 tx13
114
+ // \ | /
115
+ // final_tx
116
+ //
117
+ fn build_tx_chain (
118
+ node0 : & Node ,
119
+ ) -> (
120
+ Net ,
121
+ (
122
+ TransactionView ,
123
+ TransactionView ,
124
+ TransactionView ,
125
+ TransactionView ,
126
+ TransactionView ,
127
+ TransactionView ,
128
+ ) ,
129
+ ) {
130
+ node0. mine_until_out_bootstrap_period ( ) ;
131
+ let parent = node0. new_transaction_with_capacity ( capacity_bytes ! ( 800 ) ) ;
132
+
133
+ let script = node0. always_success_script ( ) ;
134
+ let new_output1 = CellOutputBuilder :: default ( )
135
+ . capacity ( capacity_bytes ! ( 200 ) . pack ( ) )
136
+ . lock ( script. clone ( ) )
137
+ . build ( ) ;
138
+ let new_output2 = new_output1. clone ( ) ;
139
+ let new_output3 = new_output1. clone ( ) ;
140
+
141
+ let tx1 = parent
142
+ . as_advanced_builder ( )
143
+ . set_inputs ( vec ! [ CellInput :: new( OutPoint :: new( parent. hash( ) , 0 ) , 0 ) ] )
144
+ . set_outputs ( vec ! [ new_output1, new_output2, new_output3] )
145
+ . set_outputs_data ( vec ! [ Default :: default ( ) ; 3 ] )
146
+ . build ( ) ;
147
+
148
+ let tx11 =
149
+ node0. new_transaction_with_capacity_and_index ( tx1. hash ( ) , capacity_bytes ! ( 100 ) , 0 , 0 ) ;
150
+ let tx12 =
151
+ node0. new_transaction_with_capacity_and_index ( tx1. hash ( ) , capacity_bytes ! ( 100 ) , 1 , 0 ) ;
152
+ let tx13 =
153
+ node0. new_transaction_with_capacity_and_index ( tx1. hash ( ) , capacity_bytes ! ( 100 ) , 2 , 0 ) ;
154
+
155
+ let cell_dep = node0. always_success_cell_dep ( ) ;
156
+ let final_output = CellOutputBuilder :: default ( )
157
+ . capacity ( capacity_bytes ! ( 80 ) . pack ( ) )
158
+ . lock ( script)
159
+ . build ( ) ;
160
+ let final_tx = TransactionBuilder :: default ( )
161
+ . cell_dep ( cell_dep)
162
+ . set_inputs ( vec ! [
163
+ CellInput :: new( OutPoint :: new( tx11. hash( ) , 0 ) , 0 ) ,
164
+ CellInput :: new( OutPoint :: new( tx12. hash( ) , 0 ) , 0 ) ,
165
+ CellInput :: new( OutPoint :: new( tx13. hash( ) , 0 ) , 0 ) ,
166
+ ] )
167
+ . set_outputs ( vec ! [ final_output] )
168
+ . set_outputs_data ( vec ! [ Default :: default ( ) ; 1 ] )
169
+ . build ( ) ;
170
+
171
+ let mut net = Net :: new (
172
+ "orphan_tx_test" ,
173
+ node0. consensus ( ) ,
174
+ vec ! [ SupportProtocols :: RelayV3 ] ,
175
+ ) ;
176
+ net. connect ( node0) ;
177
+
178
+ ( net, ( parent, tx1, tx11, tx12, tx13, final_tx) )
179
+ }
180
+
181
+ fn run_replay_tx (
182
+ net : & Net ,
183
+ node0 : & Node ,
184
+ tx : TransactionView ,
185
+ orphan_tx_cnt : u64 ,
186
+ pending_cnt : u64 ,
187
+ ) -> bool {
188
+ relay_tx ( net, node0, tx, ALWAYS_SUCCESS_SCRIPT_CYCLE ) ;
189
+
190
+ wait_until ( 5 , || {
191
+ let tx_pool_info = node0. get_tip_tx_pool_info ( ) ;
192
+ tx_pool_info. orphan . value ( ) == orphan_tx_cnt && tx_pool_info. pending . value ( ) == pending_cnt
193
+ } )
194
+ }
195
+
196
+ pub struct TxPoolOrphanNormal ;
197
+ impl Spec for TxPoolOrphanNormal {
198
+ fn run ( & self , nodes : & mut Vec < Node > ) {
199
+ let node0 = & nodes[ 0 ] ;
200
+ let ( net, ( parent, tx1, tx11, tx12, tx13, final_tx) ) = build_tx_chain ( node0) ;
201
+
202
+ assert ! (
203
+ run_replay_tx( & net, node0, parent, 0 , 1 ) ,
204
+ "parent sended expect nothing in orphan pool"
205
+ ) ;
206
+ assert ! (
207
+ run_replay_tx( & net, node0, tx1, 0 , 2 ) ,
208
+ "tx1 is send expect nothing in orphan pool"
209
+ ) ;
210
+ assert ! (
211
+ run_replay_tx( & net, node0, tx11, 0 , 3 ) ,
212
+ "tx11 is send expect nothing in orphan pool"
213
+ ) ;
214
+ assert ! (
215
+ run_replay_tx( & net, node0, tx12, 0 , 4 ) ,
216
+ "tx12 is send expect nothing in orphan pool"
217
+ ) ;
218
+ assert ! (
219
+ run_replay_tx( & net, node0, tx13, 0 , 5 ) ,
220
+ "tx13 is send expect nothing in orphan pool"
221
+ ) ;
222
+ assert ! (
223
+ run_replay_tx( & net, node0, final_tx, 0 , 6 ) ,
224
+ "final_tx is send expect nothing in orphan pool"
225
+ ) ;
226
+ }
227
+ }
228
+
229
+ pub struct TxPoolOrphanReverse ;
230
+ impl Spec for TxPoolOrphanReverse {
231
+ fn run ( & self , nodes : & mut Vec < Node > ) {
232
+ let node0 = & nodes[ 0 ] ;
233
+ let ( net, ( parent, tx1, tx11, tx12, tx13, final_tx) ) = build_tx_chain ( node0) ;
234
+
235
+ assert ! (
236
+ run_replay_tx( & net, node0, final_tx, 1 , 0 ) ,
237
+ "expect final_tx is in orphan pool"
238
+ ) ;
239
+
240
+ assert ! (
241
+ run_replay_tx( & net, node0, tx13, 2 , 0 ) ,
242
+ "tx13 in orphan pool"
243
+ ) ;
244
+ assert ! (
245
+ run_replay_tx( & net, node0, tx12, 3 , 0 ) ,
246
+ "tx12 is in orphan pool"
247
+ ) ;
248
+ assert ! ( run_replay_tx( & net, node0, tx11, 4 , 0 ) , "tx11 is in orphan" ) ;
249
+
250
+ assert ! ( run_replay_tx( & net, node0, tx1, 5 , 0 ) , "tx1 is in orphan" ) ;
251
+
252
+ assert ! (
253
+ run_replay_tx( & net, node0, parent, 0 , 6 ) ,
254
+ "all is in pending"
255
+ ) ;
256
+ }
257
+ }
258
+
259
+ pub struct TxPoolOrphanUnordered ;
260
+ impl Spec for TxPoolOrphanUnordered {
261
+ fn run ( & self , nodes : & mut Vec < Node > ) {
262
+ let node0 = & nodes[ 0 ] ;
263
+ let ( net, ( parent, tx1, tx11, tx12, tx13, final_tx) ) = build_tx_chain ( node0) ;
264
+
265
+ assert ! (
266
+ run_replay_tx( & net, node0, final_tx, 1 , 0 ) ,
267
+ "expect final_tx is in orphan pool"
268
+ ) ;
269
+
270
+ assert ! (
271
+ run_replay_tx( & net, node0, tx11, 2 , 0 ) ,
272
+ "tx11 in orphan pool"
273
+ ) ;
274
+ let tx12_clone = tx12. clone ( ) ;
275
+ assert ! (
276
+ run_replay_tx( & net, node0, tx12, 3 , 0 ) ,
277
+ "tx12 is in orphan pool"
278
+ ) ;
279
+
280
+ // set tx12_clone with rpc
281
+ let ret = node0
282
+ . rpc_client ( )
283
+ . send_transaction_result ( tx12_clone. data ( ) . into ( ) ) ;
284
+ assert ! ( ret
285
+ . err( )
286
+ . unwrap( )
287
+ . to_string( )
288
+ . contains( "already exist in transaction_pool" ) ) ;
289
+
290
+ assert ! (
291
+ run_replay_tx( & net, node0, parent, 3 , 1 ) ,
292
+ "parent is sent, should be in pending without change orphan pool"
293
+ ) ;
294
+ assert ! (
295
+ run_replay_tx( & net, node0, tx1, 1 , 4 ) ,
296
+ "tx1 is send, orphan pool only contains final_tx"
297
+ ) ;
298
+
299
+ assert ! (
300
+ run_replay_tx( & net, node0, tx13, 0 , 6 ) ,
301
+ "tx13 is send, orphan pool is empty"
302
+ ) ;
303
+ }
304
+ }
0 commit comments