Skip to content

Commit 3d22a8b

Browse files
author
Antoine Riard
committed
Introduce OnchainRequest
OnchainRequest aims to replace ClaimRequest/ClaimTxBumpMaterial with a common structure. This structure encodes a claiming packet composed from a PackageTemplate. Package attributes are available at the header-level are they used by OnchainTxHandler to make any aggregation, monitoring or bumping decisions.
1 parent b06c551 commit 3d22a8b

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed

lightning/src/ln/onchain_utils.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,11 @@ impl PackageTemplate {
320320
None
321321
},
322322
_ => {
323+
// Note, we may try to split on remote transaction for
324+
// which we don't have a competing one (HTLC-Success before
325+
// timelock expiration). This explain we don't panic!.
326+
// We should refactor OnchainTxHandler::block_connected to
327+
// only test equality on competing claims.
323328
return None;
324329
}
325330
}
@@ -559,6 +564,14 @@ impl PackageTemplate {
559564
}
560565
}
561566

567+
impl Default for PackageTemplate {
568+
fn default() -> Self {
569+
PackageTemplate::MalleableJusticeTx {
570+
inputs: HashMap::new(),
571+
}
572+
}
573+
}
574+
562575
impl Writeable for PackageTemplate {
563576
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
564577
match self {
@@ -639,3 +652,152 @@ impl Readable for PackageTemplate {
639652
Ok(package)
640653
}
641654
}
655+
656+
/// BumpStrategy is a basic enum to encode a fee-committing strategy. We
657+
/// may extend it in the future with other stategies like BYOF-input.
658+
#[derive(PartialEq, Clone)]
659+
pub(crate) enum BumpStrategy {
660+
RBF,
661+
CPFP
662+
}
663+
664+
impl Writeable for BumpStrategy {
665+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
666+
match self {
667+
BumpStrategy::RBF => {
668+
writer.write_all(&[0; 1])?;
669+
},
670+
BumpStrategy::CPFP => {
671+
writer.write_all(&[1; 1])?;
672+
}
673+
}
674+
Ok(())
675+
}
676+
}
677+
678+
impl Readable for BumpStrategy {
679+
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
680+
let bump_strategy = match <u8 as Readable>::read(reader)? {
681+
0 => {
682+
BumpStrategy::RBF
683+
},
684+
1 => {
685+
BumpStrategy::CPFP
686+
},
687+
_ => return Err(DecodeError::InvalidValue),
688+
};
689+
Ok(bump_strategy)
690+
}
691+
}
692+
693+
/// A structure to describe a claim content and its metadatas which is generated
694+
/// by ChannelMonitor and used by OnchainTxHandler to generate feerate-competive
695+
/// transactions.
696+
///
697+
/// Metadatas are related to multiple fields playing a role in packet lifetime.
698+
/// Once issued, it may be aggregated with other requests if it's judged safe
699+
/// and feerate opportunistic.
700+
/// Current LN fees model, pre-committed fees with update_fee adjustement, means
701+
/// that counter-signed transactions must be CPFP to be dynamically confirmed as a
702+
/// bumping strategy. If transactions aren't lockdown (i.e justice transactions) we
703+
/// may RBF them.
704+
/// Feerate previous will serve as a feerate floor between different bumping attempts.
705+
/// Height timer clocks these different bumping attempts.
706+
/// Absolute timelock defines the block barrier at which claiming isn't exclusive
707+
/// to us anymore and thus we MUST have get it solved before.
708+
/// Height original serves as a packet timestamps to prune out claim in case of reorg.
709+
/// Content embeds transactions elements to generate transaction. See PackageTemplate.
710+
#[derive(PartialEq, Clone)]
711+
pub struct OnchainRequest {
712+
// Timeout tx must have nLocktime set which means aggregating multiple
713+
// ones must take the higher nLocktime among them to satisfy all of them.
714+
// Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA
715+
// of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set.
716+
// Do simplify we mark them as non-aggregable.
717+
pub(crate) aggregation: bool,
718+
// Content may lockdown with counter-signature of our counterparty
719+
// or fully-malleable by our own. Depending on this bumping strategy
720+
// must be adapted.
721+
pub(crate) bump_strategy: BumpStrategy,
722+
// Based feerate of previous broadcast. If resources available (either
723+
// output value or utxo bumping).
724+
pub(crate) feerate_previous: u64,
725+
// At every block tick, used to check if pending claiming tx is taking too
726+
// much time for confirmation and we need to bump it.
727+
pub(crate) height_timer: Option<u32>,
728+
// Block height before which claiming is exclusive to one party,
729+
// after reaching it, claiming may be contentious.
730+
pub(crate) absolute_timelock: u32,
731+
// Tracked in case of reorg to wipe out now-superflous request.
732+
pub(crate) height_original: u32,
733+
// Content of request.
734+
pub(crate) content: PackageTemplate,
735+
}
736+
737+
impl OnchainRequest {
738+
pub(crate) fn request_merge(&mut self, req: OnchainRequest) {
739+
// We init default onchain request with first merge content
740+
if self.absolute_timelock == ::std::u32::MAX {
741+
println!("Init merging {}", req.height_original);
742+
self.height_original = req.height_original;
743+
self.content = req.content;
744+
self.absolute_timelock = req.absolute_timelock;
745+
return;
746+
}
747+
assert_eq!(self.height_original, req.height_original);
748+
if self.absolute_timelock > req.absolute_timelock {
749+
self.absolute_timelock = req.absolute_timelock;
750+
}
751+
self.content.package_merge(req.content);
752+
}
753+
}
754+
755+
impl Default for OnchainRequest {
756+
fn default() -> Self {
757+
OnchainRequest {
758+
aggregation: true,
759+
bump_strategy: BumpStrategy::RBF,
760+
feerate_previous: 0,
761+
height_timer: None,
762+
absolute_timelock: ::std::u32::MAX,
763+
height_original: 0,
764+
content: PackageTemplate::default()
765+
}
766+
}
767+
}
768+
769+
impl Writeable for OnchainRequest {
770+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
771+
self.aggregation.write(writer)?;
772+
self.bump_strategy.write(writer)?;
773+
self.feerate_previous.write(writer)?;
774+
self.height_timer.write(writer)?;
775+
self.absolute_timelock.write(writer)?;
776+
self.height_original.write(writer)?;
777+
self.content.write(writer)?;
778+
779+
Ok(())
780+
}
781+
}
782+
783+
impl Readable for OnchainRequest {
784+
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
785+
let aggregation = Readable::read(reader)?;
786+
let bump_strategy = Readable::read(reader)?;
787+
let feerate_previous = Readable::read(reader)?;
788+
let height_timer = Readable::read(reader)?;
789+
let absolute_timelock = Readable::read(reader)?;
790+
let height_original = Readable::read(reader)?;
791+
let content = Readable::read(reader)?;
792+
793+
Ok(OnchainRequest {
794+
aggregation,
795+
bump_strategy,
796+
feerate_previous,
797+
height_timer,
798+
absolute_timelock,
799+
height_original,
800+
content
801+
})
802+
}
803+
}

0 commit comments

Comments
 (0)