@@ -107,6 +107,14 @@ pub enum ConnectStyle {
107107	/// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only 
108108/// make a single `best_block_updated` call. 
109109TransactionsFirstSkippingBlocks , 
110+ 	/// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only 
111+ /// make a single `best_block_updated` call. Further, we call transactions_confirmed multiple 
112+ /// times to ensure its idempotent. 
113+ TransactionsDuplicativelyFirstSkippingBlocks , 
114+ 	/// The same as `TransactionsFirst`, however when we have multiple blocks to connect, we only 
115+ /// make a single `best_block_updated` call. Further, we call transactions_confirmed multiple 
116+ /// times to ensure its idempotent. 
117+ HighlyRedundantTransactionsFirstSkippingBlocks , 
110118	/// The same as `TransactionsFirst` when connecting blocks. During disconnection only 
111119/// `transaction_unconfirmed` is called. 
112120TransactionsFirstReorgsOnlyTip , 
@@ -121,14 +129,16 @@ impl ConnectStyle {
121129			use  core:: hash:: { BuildHasher ,  Hasher } ; 
122130			// Get a random value using the only std API to do so - the DefaultHasher 
123131			let  rand_val = std:: collections:: hash_map:: RandomState :: new ( ) . build_hasher ( ) . finish ( ) ; 
124- 			let  res = match  rand_val % 7  { 
132+ 			let  res = match  rand_val % 9  { 
125133				0  => ConnectStyle :: BestBlockFirst , 
126134				1  => ConnectStyle :: BestBlockFirstSkippingBlocks , 
127135				2  => ConnectStyle :: BestBlockFirstReorgsOnlyTip , 
128136				3  => ConnectStyle :: TransactionsFirst , 
129137				4  => ConnectStyle :: TransactionsFirstSkippingBlocks , 
130- 				5  => ConnectStyle :: TransactionsFirstReorgsOnlyTip , 
131- 				6  => ConnectStyle :: FullBlockViaListen , 
138+ 				5  => ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks , 
139+ 				6  => ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks , 
140+ 				7  => ConnectStyle :: TransactionsFirstReorgsOnlyTip , 
141+ 				8  => ConnectStyle :: FullBlockViaListen , 
132142				_ => unreachable ! ( ) , 
133143			} ; 
134144			eprintln ! ( "Using Block Connection Style: {:?}" ,  res) ; 
@@ -143,6 +153,7 @@ impl ConnectStyle {
143153pub  fn  connect_blocks < ' a ,  ' b ,  ' c ,  ' d > ( node :  & ' a  Node < ' b ,  ' c ,  ' d > ,  depth :  u32 )  -> BlockHash  { 
144154	let  skip_intermediaries = match  * node. connect_style . borrow ( )  { 
145155		ConnectStyle :: BestBlockFirstSkippingBlocks |ConnectStyle :: TransactionsFirstSkippingBlocks |
156+ 			ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks |ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks |
146157			ConnectStyle :: BestBlockFirstReorgsOnlyTip |ConnectStyle :: TransactionsFirstReorgsOnlyTip  => true , 
147158		_ => false , 
148159	} ; 
@@ -193,8 +204,32 @@ fn do_connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: Block, sk
193204				node. node . best_block_updated ( & block. header ,  height) ; 
194205				node. node . transactions_confirmed ( & block. header ,  & txdata,  height) ; 
195206			} , 
196- 			ConnectStyle :: TransactionsFirst |ConnectStyle :: TransactionsFirstSkippingBlocks |ConnectStyle :: TransactionsFirstReorgsOnlyTip  => { 
207+ 			ConnectStyle :: TransactionsFirst |ConnectStyle :: TransactionsFirstSkippingBlocks |
208+ 			ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks |ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks |
209+ 			ConnectStyle :: TransactionsFirstReorgsOnlyTip  => { 
210+ 				if  * node. connect_style . borrow ( )  == ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks  { 
211+ 					let  mut  connections = Vec :: new ( ) ; 
212+ 					for  ( block,  height)  in  node. blocks . lock ( ) . unwrap ( ) . iter ( )  { 
213+ 						if  !block. txdata . is_empty ( )  { 
214+ 							// Reconnect all transactions we've ever seen to ensure transaction connection 
215+ 							// is *really* idempotent. This is a somewhat likely deployment for some 
216+ 							// esplora implementations of chain sync which try to reduce state and 
217+ 							// complexity as much as possible. 
218+ 							// 
219+ 							// Sadly we have to clone the block here to maintain lockorder. In the 
220+ 							// future we should consider Arc'ing the blocks to avoid this. 
221+ 							connections. push ( ( block. clone ( ) ,  * height) ) ; 
222+ 						} 
223+ 					} 
224+ 					for  ( old_block,  height)  in  connections { 
225+ 						node. chain_monitor . chain_monitor . transactions_confirmed ( & old_block. header , 
226+ 							& old_block. txdata . iter ( ) . enumerate ( ) . collect :: < Vec < _ > > ( ) ,  height) ; 
227+ 					} 
228+ 				} 
197229				node. chain_monitor . chain_monitor . transactions_confirmed ( & block. header ,  & txdata,  height) ; 
230+ 				if  * node. connect_style . borrow ( )  == ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks  { 
231+ 					node. chain_monitor . chain_monitor . transactions_confirmed ( & block. header ,  & txdata,  height) ; 
232+ 				} 
198233				call_claimable_balances ( node) ; 
199234				node. chain_monitor . chain_monitor . best_block_updated ( & block. header ,  height) ; 
200235				node. node . transactions_confirmed ( & block. header ,  & txdata,  height) ; 
@@ -226,7 +261,8 @@ pub fn disconnect_blocks<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, count: u32)
226261				node. chain_monitor . chain_monitor . block_disconnected ( & orig. 0 . header ,  orig. 1 ) ; 
227262				Listen :: block_disconnected ( node. node ,  & orig. 0 . header ,  orig. 1 ) ; 
228263			} , 
229- 			ConnectStyle :: BestBlockFirstSkippingBlocks |ConnectStyle :: TransactionsFirstSkippingBlocks  => { 
264+ 			ConnectStyle :: BestBlockFirstSkippingBlocks |ConnectStyle :: TransactionsFirstSkippingBlocks |
265+ 			ConnectStyle :: HighlyRedundantTransactionsFirstSkippingBlocks |ConnectStyle :: TransactionsDuplicativelyFirstSkippingBlocks  => { 
230266				if  i == count - 1  { 
231267					node. chain_monitor . chain_monitor . best_block_updated ( & prev. 0 . header ,  prev. 1 ) ; 
232268					node. node . best_block_updated ( & prev. 0 . header ,  prev. 1 ) ; 
0 commit comments