::new(self.source_client.clone(), None); - let (header, mut proof) = finality_source.prove_block_finality(required_header).await?; - let header_id = header.id(); + const MAX_ITERATIONS: u32 = 4; + let mut iterations = 0; + let mut current_required_header = required_header; + loop { + // first find proper header (either `current_required_header`) or its descendant + let finality_source = + SubstrateFinalitySource::
::new(self.source_client.clone(), None); + let (header, mut proof) = + finality_source.prove_block_finality(current_required_header).await?; + let header_id = header.id(); + + // optimize justification before including it into the call + P::FinalityEngine::optimize_proof(&self.target_client, &header, &mut proof).await?; + + // now we have the header and its proof, but we want to minimize our losses, so let's + // check if we'll get the full refund for submitting this header + let check_result = P::FinalityEngine::check_max_expected_call_size(&header, &proof); + if let MaxExpectedCallSizeCheck::Exceeds { call_size, max_call_size } = check_result { + iterations += 1; + current_required_header = header_id.number().saturating_add(One::one()); + if iterations < MAX_ITERATIONS { + log::debug!( + target: "bridge", + "[{}] Requested to prove {} head {:?}. Selected to prove {} head {:?}. But it is too large: {} vs {}. \ + Going to select next header", + self.relay_task_name, + P::SourceChain::NAME, + required_header, + P::SourceChain::NAME, + header_id, + call_size, + max_call_size, + ); - // optimize justification before including it into the call - P::FinalityEngine::optimize_proof(&self.target_client, &header, &mut proof).await?; + continue; + } + } - log::debug!( - target: "bridge", - "[{}] Requested to prove {} head {:?}. Selected to prove {} head {:?}", - self.relay_task_name, - P::SourceChain::NAME, - required_header, - P::SourceChain::NAME, - header_id, - ); + log::debug!( + target: "bridge", + "[{}] Requested to prove {} head {:?}. Selected to prove {} head {:?} (after {} iterations)", + self.relay_task_name, + P::SourceChain::NAME, + required_header, + P::SourceChain::NAME, + header_id, + iterations, + ); - // and then craft the submit-proof call - let call = - P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); + // and then craft the submit-proof call + let call = + P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); - Ok((header_id, vec![call])) + return Ok((header_id, vec![call])); + } } }