@@ -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.
109109 TransactionsFirstSkippingBlocks ,
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 it's 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 it's idempotent.
117+ HighlyRedundantTransactionsFirstSkippingBlocks ,
110118 /// The same as `TransactionsFirst` when connecting blocks. During disconnection only
111119 /// `transaction_unconfirmed` is called.
112120 TransactionsFirstReorgsOnlyTip ,
@@ -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 :: HighlyRedundantTransactionsFirstSkippingBlocks {
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