From 644bd160ff57ecbc40ca800db459da373fa8b657 Mon Sep 17 00:00:00 2001 From: conduition Date: Sat, 16 Mar 2024 01:16:56 +0000 Subject: [PATCH] conceptually separate claimable win conditions from controlled win conditions --- src/contract/mod.rs | 73 ++++++++++++++++++++++++++++++++++------- src/contract/outcome.rs | 2 +- src/contract/split.rs | 2 +- src/lib.rs | 2 +- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/contract/mod.rs b/src/contract/mod.rs index 9f443bd..9a3c60b 100644 --- a/src/contract/mod.rs +++ b/src/contract/mod.rs @@ -201,6 +201,54 @@ impl ContractParameters { .collect() } + /// Return the set of all win conditions for which the given pubkey can claim + /// a split transaction output. In other words, this returns the possible + /// paths for a given signer to claim winnings. + /// + /// If `pubkey` belongs to one or more players, this returns all [`WinCondition`]s + /// in which the player or players are winners. + /// + /// If `pubkey` belongs to the market maker, this returns every [`WinCondition`] + /// across the entire contract. + /// + /// Returns `None` if the pubkey does not belong to any player in the DLC. + /// + /// Returns an empty `BTreeSet` if the player is part of the DLC, but isn't due to + /// receive any payouts on any DLC outcome. + pub fn win_conditions_claimable_by_pubkey( + &self, + pubkey: Point, + ) -> Option> { + // To sign as the market maker, the caller need only provide the correct secret key. + let is_market_maker = pubkey == self.market_maker.pubkey; + + let controlling_players = self.players_controlled_by_pubkey(pubkey); + + // Short circuit if this pubkey is not known. + if controlling_players.is_empty() && !is_market_maker { + return None; + } + + let mut relevant_win_conditions = BTreeSet::::new(); + for (&outcome, payout_map) in self.outcome_payouts.iter() { + // We can broadcast the split TX for any win-conditions whose player is + // controlled by `pubkey`. If we're the market maker, we have a claim + // path on every win condition. + relevant_win_conditions.extend(payout_map.keys().filter_map(|player_index| { + if is_market_maker || controlling_players.contains(player_index) { + Some(WinCondition { + player_index: *player_index, + outcome, + }) + } else { + None + } + })); + } + + Some(relevant_win_conditions) + } + /// Return the set of all win conditions which the given pubkey will need to sign /// split transactions for. /// @@ -230,18 +278,21 @@ impl ContractParameters { let mut win_conditions_to_sign = BTreeSet::::new(); for (&outcome, payout_map) in self.outcome_payouts.iter() { - // We want to sign the split TX for any win-conditions whose player is controlled - // by `pubkey`. If we're the market maker, we sign every win condition. - win_conditions_to_sign.extend(payout_map.keys().filter_map(|player_index| { - if is_market_maker || controlling_players.contains(player_index) { - Some(WinCondition { - player_index: *player_index, + // We want to sign the split TX for any win-conditions under outcomes where the + // given `pubkey` is one of the winners. If we're the market maker, we sign every + // win condition. + if is_market_maker + || controlling_players + .iter() + .any(|player_index| payout_map.contains_key(player_index)) + { + win_conditions_to_sign.extend(payout_map.keys().map(|&player_index| { + WinCondition { + player_index, outcome, - }) - } else { - None - } - })); + } + })); + } } Some(win_conditions_to_sign) diff --git a/src/contract/outcome.rs b/src/contract/outcome.rs index aa04237..40ef899 100644 --- a/src/contract/outcome.rs +++ b/src/contract/outcome.rs @@ -323,7 +323,7 @@ pub(crate) fn verify_outcome_tx_aggregated_signatures( // We only need to verify signatures on outcomes where our pubkey might // win something. let relevant_outcomes: BTreeSet = params - .win_conditions_controlled_by_pubkey(our_pubkey) + .win_conditions_claimable_by_pubkey(our_pubkey) .ok_or(Error)? .into_iter() .map(|win_cond| win_cond.outcome) diff --git a/src/contract/split.rs b/src/contract/split.rs index b478524..73b835f 100644 --- a/src/contract/split.rs +++ b/src/contract/split.rs @@ -285,7 +285,7 @@ pub(crate) fn verify_split_tx_aggregated_signatures( // We only need to verify signatures on win conditions where our pubkey might // win something. let relevant_win_conditions: BTreeSet = params - .win_conditions_controlled_by_pubkey(our_pubkey) + .win_conditions_claimable_by_pubkey(our_pubkey) .ok_or(Error)?; let batch: Vec = relevant_win_conditions diff --git a/src/lib.rs b/src/lib.rs index a8f9a42..112f9c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -476,7 +476,7 @@ impl SignedContract { let relevant_win_conditions = self .dlc .params - .win_conditions_controlled_by_pubkey(player_pubkey)?; + .win_conditions_claimable_by_pubkey(player_pubkey)?; let relevant_outcomes: BTreeSet = relevant_win_conditions .iter()