Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step 7, remaining todos #57

Draft
wants to merge 13 commits into
base: 20241229-potato-handler
Choose a base branch
from
102 changes: 84 additions & 18 deletions src/channel_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use clvmr::allocator::NodePtr;

use crate::channel_handler::game_handler::TheirTurnResult;
use crate::channel_handler::types::{
AcceptTransactionState, CachedPotatoRegenerateLastHop, ChannelCoin, ChannelCoinInfo,
ChannelCoinSpendInfo, ChannelCoinSpentResult, ChannelHandlerEnv, ChannelHandlerInitiationData,
CachedPotatoRegenerateLastHop, ChannelCoin, ChannelCoinInfo, ChannelCoinSpendInfo,
ChannelCoinSpentResult, ChannelHandlerEnv, ChannelHandlerInitiationData,
ChannelHandlerInitiationResult, ChannelHandlerPrivateKeys, ChannelHandlerUnrollSpendInfo,
CoinDataForReward, CoinSpentAccept, CoinSpentDisposition, CoinSpentInformation,
CoinSpentMoveUp, CoinSpentResult, DispositionResult, GameStartInfo, HandshakeResult, LiveGame,
Expand Down Expand Up @@ -1485,15 +1485,41 @@ impl ChannelHandler {
let initial_potato = self.is_initial_potato();

debug!(
"{} ALIGN GAME STATES: initiated {} my state {} coin state {}",
initial_potato,
self.initiated_on_chain,
self.current_state_number,
self.unroll.coin.state_number,
"{initial_potato} ALIGN GAME STATES: initiated {} my state {} coin state {}",
self.initiated_on_chain, self.current_state_number, self.unroll.coin.state_number,
);

debug!(
"{initial_potato} cached state {:?}",
self.cached_last_action
);
debug!("{initial_potato} #game coins {}", coins.len());

let mover_puzzle_hash = private_to_public_key(&self.referee_private_key());
for game_coin in coins.iter() {
if let Some(CachedPotatoRegenerateLastHop::PotatoAccept(cached)) =
&self.cached_last_action
{
if *game_coin == cached.puzzle_hash {
let coin_id = CoinString::from_parts(
&unroll_coin.to_coin_id(),
&game_coin.clone(),
&cached.live_game.get_amount(),
);
debug!("{initial_potato} set coin for accept");
res.insert(
coin_id,
OnChainGameState {
game_id: cached.live_game.game_id.clone(),
puzzle_hash: game_coin.clone(),
our_turn: cached.live_game.is_my_turn(),
accept: None,
},
);
continue;
}
}

for live_game in self.live_games.iter_mut() {
debug!(
"live game id {:?} try to use coin {game_coin:?}",
Expand All @@ -1504,6 +1530,7 @@ impl ChannelHandler {
game_coin,
self.current_state_number,
)?;

if let Some((_my_turn, rewind_state)) = rewind_target {
debug!("{} rewind target state was {rewind_state}", initial_potato);
debug!("mover puzzle hash is {:?}", mover_puzzle_hash);
Expand All @@ -1523,14 +1550,14 @@ impl ChannelHandler {
game_id: live_game.game_id.clone(),
puzzle_hash: game_coin.clone(),
our_turn: live_game.is_my_turn(),
accept: AcceptTransactionState::Waiting,
accept: None,
},
);
}
}
}

assert_eq!(res.is_empty(), self.live_games.is_empty());
// assert_eq!(res.is_empty(), coins.is_empty());

Ok(res)
}
Expand Down Expand Up @@ -1702,11 +1729,47 @@ impl ChannelHandler {
let mut cla = None;
swap(&mut cla, &mut self.cached_last_action);
match cla {
Some(CachedPotatoRegenerateLastHop::PotatoCreatedGame(_, _, _)) => {
todo!();
Some(CachedPotatoRegenerateLastHop::PotatoCreatedGame(
ids,
my_contrib,
their_contrib,
)) => {
// Can't restart games on chain so rewind.
self.my_allocated_balance -= my_contrib;
self.their_allocated_balance -= their_contrib;
let remove_ids: Vec<usize> = self
.live_games
.iter()
.enumerate()
.filter_map(|(i, g)| {
if ids.iter().any(|i| g.game_id == *i) {
Some(i)
} else {
None
}
})
.collect();
for id in remove_ids.into_iter() {
self.live_games.remove(id);
}
Ok(None)
}
Some(CachedPotatoRegenerateLastHop::PotatoAccept(_)) => {
todo!();
Some(CachedPotatoRegenerateLastHop::PotatoAccept(mut accept)) => {
debug!("{} redo move is an accept", self.is_initial_potato());
let transaction = accept
.live_game
.get_transaction_for_timeout(env.allocator, coin)?;

debug!("{} redo accept data {accept:?}", self.is_initial_potato());
let outcome_puzzle_hash = accept.live_game.outcome_puzzle_hash(env.allocator)?;
Ok(transaction.map(|t| {
GameAction::RedoAccept(
accept.live_game.game_id.clone(),
coin.clone(),
outcome_puzzle_hash,
Box::new(t),
)
}))
}
Some(CachedPotatoRegenerateLastHop::PotatoMoveHappening(move_data)) => {
let game_idx = self.get_game_by_id(&move_data.game_id)?;
Expand Down Expand Up @@ -1841,11 +1904,14 @@ impl ChannelHandler {
game_id: &GameID,
coin: &CoinString,
) -> Result<Option<RefereeOnChainTransaction>, Error> {
let game_idx = self.get_game_by_id(game_id)?;
let tx = self.live_games[game_idx].get_transaction_for_timeout(env.allocator, coin)?;
// Game is done one way or another.
self.live_games.remove(game_idx);
Ok(tx)
if let Ok(game_idx) = self.get_game_by_id(game_id) {
let tx = self.live_games[game_idx].get_transaction_for_timeout(env.allocator, coin)?;
// Game is done one way or another.
self.live_games.remove(game_idx);
Ok(tx)
} else {
Ok(None)
}
}

// the vanilla coin we get and each reward coin are all sent to the referee
Expand Down
2 changes: 1 addition & 1 deletion src/channel_handler/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ pub struct OnChainGameState {
pub game_id: GameID,
pub puzzle_hash: PuzzleHash,
pub our_turn: bool,
pub accept: AcceptTransactionState,
pub accept: Option<RefereeOnChainTransaction>,
}

impl LiveGame {
Expand Down
2 changes: 1 addition & 1 deletion src/peer_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ impl SynchronousGameCradle {
let msg = if let Some(msg) = self.state.outbound_messages.pop_back() {
msg
} else {
todo!();
return Err(Error::StrErr("no message to replace".to_string()));
};

let doc = bson::Document::from_reader(&mut msg.as_slice()).into_gen()?;
Expand Down
30 changes: 23 additions & 7 deletions src/potato_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,9 @@ impl PotatoHandler {
Some(GameAction::RedoMove(_game_id, _coin, _new_ph, _transaction)) => {
Err(Error::StrErr("redo move when not on chain".to_string()))
}
Some(GameAction::RedoAccept(_, _, _, _)) => {
Err(Error::StrErr("redo accept when not on chain".to_string()))
}
Some(GameAction::Accept(game_id)) => {
let (sigs, amount) = {
let ch = self.channel_handler_mut()?;
Expand Down Expand Up @@ -1466,7 +1469,9 @@ impl PotatoHandler {
self.game_action_queue.push_back(action);

if !matches!(self.have_potato, PotatoState::Present) {
self.request_potato(penv)?;
if matches!(self.have_potato, PotatoState::Absent) {
self.request_potato(penv)?;
}
return Ok(());
}

Expand Down Expand Up @@ -1596,7 +1601,6 @@ impl PotatoHandler {
def.game_id,
player_ch.game_is_my_turn(&def.game_id)
);
assert_eq!(player_ch.game_is_my_turn(&def.game_id), Some(def.our_turn));
}

// Register each coin that corresponds to a game.
Expand Down Expand Up @@ -1704,7 +1708,9 @@ impl<G: ToLocalUI + BootstrapTowardWallet + WalletSpendInterface + PacketSender,
});

if !matches!(self.have_potato, PotatoState::Present) {
self.request_potato(penv)?;
if matches!(self.have_potato, PotatoState::Absent) {
self.request_potato(penv)?;
}
return Ok(game_id_list);
}

Expand Down Expand Up @@ -1752,11 +1758,21 @@ impl<G: ToLocalUI + BootstrapTowardWallet + WalletSpendInterface + PacketSender,
G: 'a,
R: 'a,
{
if let HandshakeState::OnChain(on_chain) = &mut self.handshake_state {
if on_chain.shut_down(penv, conditions.clone())? {
self.handshake_state = HandshakeState::Completed;
let mut hs_state = HandshakeState::Completed;
swap(&mut hs_state, &mut self.handshake_state);
match hs_state {
HandshakeState::OnChain(mut on_chain) => {
if on_chain.shut_down(penv, conditions.clone())? {
self.channel_handler = Some(on_chain.into_channel_handler());
self.handshake_state = HandshakeState::Completed;
} else {
self.handshake_state = HandshakeState::OnChain(on_chain);
}
return Ok(());
}
x => {
self.handshake_state = x;
}
return Ok(());
}

if !matches!(self.handshake_state, HandshakeState::Finished(_)) {
Expand Down
64 changes: 49 additions & 15 deletions src/potato_handler/on_chain.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Borrow;
use std::collections::{HashMap, VecDeque};
use std::rc::Rc;

Expand All @@ -6,9 +7,7 @@ use rand::Rng;

use log::debug;

use crate::channel_handler::types::{
AcceptTransactionState, CoinSpentInformation, OnChainGameState, ReadableMove,
};
use crate::channel_handler::types::{CoinSpentInformation, OnChainGameState, ReadableMove};
use crate::channel_handler::ChannelHandler;
use crate::common::types::{
Amount, CoinCondition, CoinSpend, CoinString, Error, GameID, Hash, IntoErr, Program,
Expand All @@ -18,7 +17,7 @@ use crate::potato_handler::types::{
BootstrapTowardWallet, GameAction, PacketSender, PeerEnv, PotatoHandlerImpl, PotatoState,
ToLocalUI, WalletSpendInterface,
};
use crate::referee::TheirTurnCoinSpentResult;
use crate::referee::{RefereeOnChainTransaction, TheirTurnCoinSpentResult};
use crate::shutdown::ShutdownConditions;

pub struct OnChainPotatoHandler {
Expand Down Expand Up @@ -62,6 +61,10 @@ impl PotatoHandlerImpl for OnChainPotatoHandler {
&mut self.player_ch
}

fn into_channel_handler(self) -> ChannelHandler {
self.player_ch
}

fn check_game_coin_spent<'a, G, R: Rng + 'a>(
&mut self,
penv: &mut dyn PeerEnv<'a, G, R>,
Expand Down Expand Up @@ -226,24 +229,39 @@ impl PotatoHandlerImpl for OnChainPotatoHandler {
let (env, system_interface) = penv.env();
debug!("{initial_potato} timeout coin {coin_id:?}, do accept");

let result_transaction =
self.player_ch
.accept_or_timeout_game_on_chain(env, &game_def.game_id, coin_id)?;
if let Some(tx) = &game_def.accept {
debug!("{initial_potato} accept tx {tx:?}");
self.have_potato = PotatoState::Present;

self.have_potato = PotatoState::Present;
if let Some(tx) = result_transaction {
debug!("{initial_potato} accept: have transaction {tx:?}");
self.have_potato = PotatoState::Absent;
system_interface.spend_transaction_and_add_fee(&SpendBundle {
name: Some(format!("{initial_potato} accept transaction")),
name: Some("redo move".to_string()),
spends: vec![CoinSpend {
coin: coin_id.clone(),
bundle: tx.bundle.clone(),
}],
})?;
} else {
debug!("{initial_potato} Accepted game when our share was zero");
debug!("when action queue is {:?}", self.game_action_queue);
let result_transaction = self.player_ch.accept_or_timeout_game_on_chain(
env,
&game_def.game_id,
coin_id,
)?;

self.have_potato = PotatoState::Present;
if let Some(tx) = result_transaction {
debug!("{initial_potato} accept: have transaction {tx:?}");
self.have_potato = PotatoState::Absent;
system_interface.spend_transaction_and_add_fee(&SpendBundle {
name: Some(format!("{initial_potato} accept transaction")),
spends: vec![CoinSpend {
coin: coin_id.clone(),
bundle: tx.bundle.clone(),
}],
})?;
} else {
debug!("{initial_potato} Accepted game when our share was zero");
debug!("when action queue is {:?}", self.game_action_queue);
}
}

// XXX Have a notification for this.
Expand Down Expand Up @@ -405,6 +423,22 @@ impl PotatoHandlerImpl for OnChainPotatoHandler {
)?;
Ok(())
}
GameAction::RedoAccept(_game_id, coin, _new_ph, tx) => {
let (_env, system_interface) = penv.env();
// Wait for timeout.
if let Some(def) = self.game_map.get_mut(&coin) {
self.have_potato = PotatoState::Absent;
debug!("{initial_potato} redo accept: register for timeout {coin:?}");
let tx_borrow: &RefereeOnChainTransaction = tx.borrow();
def.accept = Some(tx_borrow.clone());
system_interface.register_coin(
&coin,
&self.channel_timeout,
Some("redo accept wait"),
)?;
}
Ok(())
}
GameAction::Accept(game_id) => {
let current_coin = get_current_coin(&game_id)?;
let my_turn = self.player_ch.game_is_my_turn(&game_id);
Expand All @@ -413,7 +447,7 @@ impl PotatoHandlerImpl for OnChainPotatoHandler {
);

if let Some(coin_def) = self.game_map.get_mut(&current_coin) {
coin_def.accept = AcceptTransactionState::Waiting;
coin_def.accept = None;
}

Ok(())
Expand Down
11 changes: 11 additions & 0 deletions src/potato_handler/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,12 @@ pub enum GameAction {
PuzzleHash,
Box<RefereeOnChainTransaction>,
),
RedoAccept(
GameID,
CoinString,
PuzzleHash,
Box<RefereeOnChainTransaction>,
),
Accept(GameID),
Shutdown(Rc<dyn ShutdownConditions>),
}
Expand All @@ -427,6 +433,9 @@ impl std::fmt::Debug for GameAction {
GameAction::RedoMove(gi, cs, ph, rt) => {
write!(formatter, "RedoMove({gi:?},{cs:?},{ph:?},{rt:?})")
}
GameAction::RedoAccept(gi, cs, ph, rt) => {
write!(formatter, "RedoAccept({gi:?},{cs:?},{ph:?},{rt:?})")
}
GameAction::Accept(gi) => write!(formatter, "Accept({gi:?})"),
GameAction::Shutdown(_) => write!(formatter, "Shutdown(..)"),
}
Expand All @@ -449,6 +458,8 @@ pub trait PotatoHandlerImpl {

fn channel_handler_mut(&mut self) -> &mut ChannelHandler;

fn into_channel_handler(self) -> ChannelHandler;

fn check_game_coin_spent<'a, G, R: Rng + 'a>(
&mut self,
penv: &mut dyn PeerEnv<'a, G, R>,
Expand Down
Loading
Loading