Event(ClaimEvent),
}
+/// Represents the different feerates a pending request can use when generating a claim.
+pub(crate) enum FeerateStrategy {
+ /// We must pick the highest between the most recently used and the current feerate estimate.
+ HighestOfPreviousOrNew,
+ /// We must force a bump of the most recently used feerate, either by using the current feerate
+ /// estimate if it's higher, or manually bumping.
+ ForceBump,
+}
+
/// OnchainTxHandler receives claiming requests, aggregates them if it's sound, broadcast and
/// do RBF bumping if possible.
#[derive(Clone)]
signer.provide_channel_parameters(&channel_parameters);
let pending_claim_requests_len: u64 = Readable::read(reader)?;
- let mut pending_claim_requests = HashMap::with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
+ let mut pending_claim_requests = hash_map_with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
for _ in 0..pending_claim_requests_len {
pending_claim_requests.insert(Readable::read(reader)?, Readable::read(reader)?);
}
let claimable_outpoints_len: u64 = Readable::read(reader)?;
- let mut claimable_outpoints = HashMap::with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
+ let mut claimable_outpoints = hash_map_with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128));
for _ in 0..claimable_outpoints_len {
let outpoint = Readable::read(reader)?;
let ancestor_claim_txid = Readable::read(reader)?;
prev_holder_commitment: None,
signer,
channel_transaction_parameters: channel_parameters,
- pending_claim_requests: HashMap::new(),
- claimable_outpoints: HashMap::new(),
+ pending_claim_requests: new_hash_map(),
+ claimable_outpoints: new_hash_map(),
locktimed_packages: BTreeMap::new(),
onchain_events_awaiting_threshold_conf: Vec::new(),
pending_claim_events: Vec::new(),
/// invoking this every 30 seconds, or lower if running in an environment with spotty
/// connections, like on mobile.
pub(super) fn rebroadcast_pending_claims<B: Deref, F: Deref, L: Logger>(
- &mut self, current_height: u32, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>,
- logger: &L,
+ &mut self, current_height: u32, feerate_strategy: FeerateStrategy, broadcaster: &B,
+ fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
)
where
B::Target: BroadcasterInterface,
bump_requests.push((*claim_id, request.clone()));
}
for (claim_id, request) in bump_requests {
- self.generate_claim(current_height, &request, false /* force_feerate_bump */, fee_estimator, logger)
+ self.generate_claim(current_height, &request, &feerate_strategy, fee_estimator, logger)
.map(|(_, new_feerate, claim)| {
let mut bumped_feerate = false;
if let Some(mut_request) = self.pending_claim_requests.get_mut(&claim_id) {
/// Panics if there are signing errors, because signing operations in reaction to on-chain
/// events are not expected to fail, and if they do, we may lose funds.
fn generate_claim<F: Deref, L: Logger>(
- &mut self, cur_height: u32, cached_request: &PackageTemplate, force_feerate_bump: bool,
+ &mut self, cur_height: u32, cached_request: &PackageTemplate, feerate_strategy: &FeerateStrategy,
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
) -> Option<(u32, u64, OnchainClaim)>
where F::Target: FeeEstimator,
if cached_request.is_malleable() {
if cached_request.requires_external_funding() {
let target_feerate_sat_per_1000_weight = cached_request.compute_package_feerate(
- fee_estimator, ConfirmationTarget::OnChainSweep, force_feerate_bump
+ fee_estimator, ConfirmationTarget::OnChainSweep, feerate_strategy,
);
if let Some(htlcs) = cached_request.construct_malleable_package_with_external_funding(self) {
return Some((
let predicted_weight = cached_request.package_weight(&self.destination_script);
if let Some((output_value, new_feerate)) = cached_request.compute_package_output(
predicted_weight, self.destination_script.dust_value().to_sat(),
- force_feerate_bump, fee_estimator, logger,
+ feerate_strategy, fee_estimator, logger,
) {
assert!(new_feerate != 0);
let conf_target = ConfirmationTarget::OnChainSweep;
let package_target_feerate_sat_per_1000_weight = cached_request
- .compute_package_feerate(fee_estimator, conf_target, force_feerate_bump);
+ .compute_package_feerate(fee_estimator, conf_target, feerate_strategy);
if let Some(input_amount_sat) = output.funding_amount {
let fee_sat = input_amount_sat - tx.output.iter().map(|output| output.value).sum::<u64>();
let commitment_tx_feerate_sat_per_1000_weight =
if let Some(claim_id) = claim_id {
if let Some(claim) = self.pending_claim_requests.remove(&claim_id) {
for outpoint in claim.outpoints() {
- self.claimable_outpoints.remove(&outpoint);
+ self.claimable_outpoints.remove(outpoint);
}
}
} else {
// height timer expiration (i.e in how many blocks we're going to take action).
for mut req in preprocessed_requests {
if let Some((new_timer, new_feerate, claim)) = self.generate_claim(
- cur_height, &req, true /* force_feerate_bump */, &*fee_estimator, &*logger,
+ cur_height, &req, &FeerateStrategy::ForceBump, &*fee_estimator, &*logger,
) {
req.set_timer(new_timer);
req.set_feerate(new_feerate);
claim_id
},
};
- debug_assert!(self.pending_claim_requests.get(&claim_id).is_none());
+ // Because fuzzing can cause hash collisions, we can end up with conflicting claim
+ // ids here, so we only assert when not fuzzing.
+ debug_assert!(cfg!(fuzzing) || self.pending_claim_requests.get(&claim_id).is_none());
for k in req.outpoints() {
log_info!(logger, "Registering claiming request for {}:{}", k.txid, k.vout);
self.claimable_outpoints.insert(k.clone(), (claim_id, conf_height));
F::Target: FeeEstimator,
{
log_debug!(logger, "Updating claims view at height {} with {} matched transactions in block {}", cur_height, txn_matched.len(), conf_height);
- let mut bump_candidates = HashMap::new();
+ let mut bump_candidates = new_hash_map();
for tx in txn_matched {
// Scan all input to verify is one of the outpoint spent is of interest for us
let mut claimed_outputs_material = Vec::new();
log_trace!(logger, "Bumping {} candidates", bump_candidates.len());
for (claim_id, request) in bump_candidates.iter() {
if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
- cur_height, &request, true /* force_feerate_bump */, &*fee_estimator, &*logger,
+ cur_height, &request, &FeerateStrategy::ForceBump, &*fee_estimator, &*logger,
) {
match bump_claim {
OnchainClaim::Tx(bump_tx) => {
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator,
{
- let mut bump_candidates = HashMap::new();
+ let mut bump_candidates = new_hash_map();
let onchain_events_awaiting_threshold_conf =
self.onchain_events_awaiting_threshold_conf.drain(..).collect::<Vec<_>>();
for entry in onchain_events_awaiting_threshold_conf {
// `height` is the height being disconnected, so our `current_height` is 1 lower.
let current_height = height - 1;
if let Some((new_timer, new_feerate, bump_claim)) = self.generate_claim(
- current_height, &request, true /* force_feerate_bump */, fee_estimator, logger
+ current_height, &request, &FeerateStrategy::ForceBump, fee_estimator, logger
) {
request.set_timer(new_timer);
request.set_feerate(new_feerate);