Skip to content

Commit 323b199

Browse files
authored
Merge pull request #2564 from subspace/fix-flaky-fp-tests
Retry produce bundle with the same slot in the domain test
2 parents 981bb42 + 661d2bb commit 323b199

File tree

10 files changed

+36
-2
lines changed

10 files changed

+36
-2
lines changed

crates/subspace-malicious-operator/src/malicious_bundle_producer.rs

+1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ where
140140
operator_keystore.clone(),
141141
// The malicious operator doesn't skip empty bundle
142142
false,
143+
false,
143144
);
144145

145146
let malicious_bundle_tamper =

crates/subspace-malicious-operator/src/malicious_domain_instance_starter.rs

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ where
148148
domain_message_receiver,
149149
provider: eth_provider,
150150
skip_empty_bundle_production: true,
151+
skip_out_of_order_slot: false,
151152
// Always set it to `None` to not running the normal bundle producer
152153
maybe_operator_id: None,
153154
};

crates/subspace-node/src/commands/run/domain.rs

+1
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ where
483483
domain_message_receiver,
484484
provider: eth_provider,
485485
skip_empty_bundle_production: true,
486+
skip_out_of_order_slot: false,
486487
maybe_operator_id: operator_id,
487488
};
488489

domains/client/domain-operator/src/domain_bundle_producer.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use sc_client_api::{AuxStore, BlockBackend};
77
use sp_api::ProvideRuntimeApi;
88
use sp_block_builder::BlockBuilder;
99
use sp_blockchain::HeaderBackend;
10+
use sp_consensus_slots::Slot;
1011
use sp_domains::core_api::DomainCoreApi;
1112
use sp_domains::{
1213
Bundle, BundleProducerElectionApi, DomainId, DomainsApi, OperatorId, OperatorPublicKey,
@@ -40,7 +41,13 @@ where
4041
keystore: KeystorePtr,
4142
bundle_producer_election_solver: BundleProducerElectionSolver<Block, CBlock, CClient>,
4243
domain_bundle_proposer: DomainBundleProposer<Block, Client, CBlock, CClient, TransactionPool>,
44+
// TODO: both `skip_empty_bundle_production` and `skip_out_of_order_slot` are only used in the
45+
// tests, we should introduce a trait for `DomainBundleProducer` and use a wrapper of `DomainBundleProducer`
46+
// in the test, both `skip_empty_bundle_production` and `skip_out_of_order_slot` should move into the wrapper
47+
// to keep the production code clean.
4348
skip_empty_bundle_production: bool,
49+
skip_out_of_order_slot: bool,
50+
last_processed_slot: Option<Slot>,
4451
}
4552

4653
impl<Block, CBlock, Client, CClient, TransactionPool> Clone
@@ -59,6 +66,8 @@ where
5966
bundle_producer_election_solver: self.bundle_producer_election_solver.clone(),
6067
domain_bundle_proposer: self.domain_bundle_proposer.clone(),
6168
skip_empty_bundle_production: self.skip_empty_bundle_production,
69+
skip_out_of_order_slot: self.skip_out_of_order_slot,
70+
last_processed_slot: None,
6271
}
6372
}
6473
}
@@ -92,6 +101,7 @@ where
92101
bundle_sender: Arc<BundleSender<Block, CBlock>>,
93102
keystore: KeystorePtr,
94103
skip_empty_bundle_production: bool,
104+
skip_out_of_order_slot: bool,
95105
) -> Self {
96106
let bundle_producer_election_solver = BundleProducerElectionSolver::<Block, CBlock, _>::new(
97107
keystore.clone(),
@@ -106,6 +116,8 @@ where
106116
bundle_producer_election_solver,
107117
domain_bundle_proposer,
108118
skip_empty_bundle_production,
119+
skip_out_of_order_slot,
120+
last_processed_slot: None,
109121
}
110122
}
111123

@@ -131,7 +143,16 @@ where
131143
// already processed a block higher than the local best and submitted the receipt to
132144
// the parent chain, we ought to catch up with the consensus block processing before
133145
// producing new bundle.
134-
!domain_best_number.is_zero() && domain_best_number <= head_receipt_number
146+
let is_operator_lagging =
147+
!domain_best_number.is_zero() && domain_best_number <= head_receipt_number;
148+
149+
let skip_out_of_order_slot = self.skip_out_of_order_slot
150+
&& self
151+
.last_processed_slot
152+
.map(|last_slot| last_slot >= slot)
153+
.unwrap_or(false);
154+
155+
is_operator_lagging || skip_out_of_order_slot
135156
};
136157

137158
if should_skip_slot {
@@ -182,6 +203,8 @@ where
182203
return Ok(None);
183204
}
184205

206+
self.last_processed_slot.replace(slot);
207+
185208
info!("🔖 Producing bundle at slot {:?}", slot_info.slot);
186209

187210
let to_sign = bundle_header.hash();

domains/client/domain-operator/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ pub struct OperatorParams<
176176
pub domain_confirmation_depth: NumberFor<Block>,
177177
pub block_import: SharedBlockImport<Block>,
178178
pub skip_empty_bundle_production: bool,
179+
pub skip_out_of_order_slot: bool,
179180
}
180181

181182
pub(crate) fn load_execution_receipt_by_domain_hash<Block, CBlock, Client>(

domains/client/domain-operator/src/operator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ where
136136
params.bundle_sender,
137137
params.keystore.clone(),
138138
params.skip_empty_bundle_production,
139+
params.skip_out_of_order_slot,
139140
);
140141

141142
let fraud_proof_generator = FraudProofGenerator::new(

domains/client/domain-operator/src/tests.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2965,6 +2965,7 @@ async fn stale_and_in_future_bundle_should_be_rejected() {
29652965
Arc::new(bundle_sender),
29662966
alice.operator.keystore.clone(),
29672967
false,
2968+
false,
29682969
)
29692970
};
29702971

@@ -3882,6 +3883,7 @@ async fn test_bad_receipt_chain() {
38823883
Arc::new(bundle_sender),
38833884
alice.operator.keystore.clone(),
38843885
false,
3886+
false,
38853887
)
38863888
};
38873889

domains/service/src/domain.rs

+3
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ where
231231
pub domain_message_receiver: TracingUnboundedReceiver<ChainTxPoolMsg>,
232232
pub provider: Provider,
233233
pub skip_empty_bundle_production: bool,
234+
pub skip_out_of_order_slot: bool,
234235
}
235236

236237
/// Builds service for a domain full node.
@@ -328,6 +329,7 @@ where
328329
domain_message_receiver,
329330
provider,
330331
skip_empty_bundle_production,
332+
skip_out_of_order_slot,
331333
} = domain_params;
332334

333335
// TODO: Do we even need block announcement on domain node?
@@ -446,6 +448,7 @@ where
446448
domain_confirmation_depth,
447449
block_import,
448450
skip_empty_bundle_production,
451+
skip_out_of_order_slot,
449452
},
450453
)
451454
.await?;

domains/test/service/src/domain.rs

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ where
228228
domain_message_receiver,
229229
provider: DefaultProvider,
230230
skip_empty_bundle_production,
231+
skip_out_of_order_slot: true,
231232
maybe_operator_id,
232233
};
233234

test/subspace-test-service/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,8 @@ impl MockConsensusNode {
529529
NewSlot,
530530
OpaqueBundle<NumberFor<Block>, Hash, DomainHeader, Balance>,
531531
) {
532+
let slot = self.produce_slot();
532533
for _ in 0..MAX_PRODUCE_BUNDLE_TRY {
533-
let slot = self.produce_slot();
534534
if let Some(bundle) = self.notify_new_slot_and_wait_for_bundle(slot).await {
535535
return (slot, bundle);
536536
}

0 commit comments

Comments
 (0)