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

20241007 potato go on chain #44

Draft
wants to merge 35 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3585869
Starting to add go on chain to potato handler
prozacchiwawa Oct 7, 2024
be745e4
WIP
prozacchiwawa Oct 8, 2024
f8bad49
Completed the loop logically but not spendable yet
prozacchiwawa Oct 9, 2024
668cafc
Organic move on chain is spending the channel coin and we need to pus…
prozacchiwawa Oct 14, 2024
c3579b9
We're spending the unroll coin i think at the right state along with …
prozacchiwawa Oct 18, 2024
851ef70
WIP: routed in puzzle and solution for requested coins
prozacchiwawa Nov 7, 2024
3aadb66
WIP: we're now starting to engage with spent handlers in channel handler
prozacchiwawa Nov 7, 2024
aa36e29
Merge remote-tracking branch 'upstream/main' into 20241007-potato-go-…
prozacchiwawa Nov 7, 2024
36fe1f1
Merge remote-tracking branch 'upstream/main' into 20241007-potato-go-…
prozacchiwawa Nov 7, 2024
42b305c
fmt + clippy
prozacchiwawa Nov 8, 2024
aadbd68
clippy
prozacchiwawa Nov 8, 2024
b7cd791
Merge up
prozacchiwawa Nov 8, 2024
77e1ee6
Change comment language
prozacchiwawa Nov 8, 2024
be2444f
Small wip
prozacchiwawa Nov 9, 2024
5442af6
Up to spend, wrong puzzle provided (WIP)
prozacchiwawa Nov 12, 2024
32d43fe
More parameterization which gives us the freedom to match things
prozacchiwawa Nov 12, 2024
9ba499e
Ensure that we can give a correct spend of the channel coin downstrea…
prozacchiwawa Nov 14, 2024
08cda55
Add decision about whether we add our half of the signature or whethe…
prozacchiwawa Nov 14, 2024
54e7d53
Add an unroll time lock into channel handler. This is needed to prev…
prozacchiwawa Nov 14, 2024
565ccdb
Rename get_unroll_coin_transaction to get_create_unroll_coin_transact…
prozacchiwawa Nov 14, 2024
4844ccc
Timeout
prozacchiwawa Nov 14, 2024
873fc26
Converting to a better rendition of the state machine given a new und…
prozacchiwawa Nov 14, 2024
1832cb8
Small cleanup: deduplicate some code
prozacchiwawa Nov 14, 2024
2f22c49
Fix up some flow, fallout of deduplication. Primed for the next roun…
prozacchiwawa Nov 14, 2024
5144436
Fix up timeout reporting and filtering in full coinset reports in pee…
prozacchiwawa Nov 14, 2024
4bb00eb
We can spend the unroll coin after the timeout (from the first user's…
prozacchiwawa Nov 15, 2024
d713df5
both players complete on chain transition. We need to populate finis…
prozacchiwawa Nov 16, 2024
328159f
Passing test
prozacchiwawa Nov 16, 2024
e8f4fc8
fmt
prozacchiwawa Nov 16, 2024
5a8309d
Fix most of the clippy traffic.
prozacchiwawa Nov 16, 2024
8bc013d
Ensure we can find the clone method. Figure out something better
prozacchiwawa Nov 16, 2024
7ce16b8
Deref
prozacchiwawa Nov 16, 2024
4880720
fmt + clippy
prozacchiwawa Nov 16, 2024
a0db32e
clippy update
prozacchiwawa Nov 16, 2024
ab2cf99
fmt
prozacchiwawa Nov 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 134 additions & 48 deletions src/channel_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,23 @@ use crate::channel_handler::types::{
CachedPotatoRegenerateLastHop, ChannelCoin, ChannelCoinInfo, ChannelCoinSpendInfo,
ChannelCoinSpentResult, ChannelHandlerEnv, ChannelHandlerInitiationData,
ChannelHandlerInitiationResult, ChannelHandlerPrivateKeys, ChannelHandlerUnrollSpendInfo,
CoinSpentAccept, CoinSpentDisposition, CoinSpentMoveUp, CoinSpentResult, DispositionResult,
GameStartInfo, HandshakeResult, LiveGame, MoveResult, OnChainGameCoin, PotatoAcceptCachedData,
PotatoMoveCachedData, PotatoSignatures, ReadableMove, UnrollCoin, UnrollCoinConditionInputs,
CoinDataForReward, CoinSpentAccept, CoinSpentDisposition, CoinSpentMoveUp, CoinSpentResult,
DispositionResult, GameStartInfo, HandshakeResult, LiveGame, MoveResult, OnChainGameCoin,
PotatoAcceptCachedData, PotatoMoveCachedData, PotatoSignatures, ReadableMove, UnrollCoin,
UnrollCoinConditionInputs, UnrollTarget,
};
use crate::common::constants::CREATE_COIN;
use crate::common::standard_coin::{
private_to_public_key, puzzle_for_pk, puzzle_for_synthetic_public_key, puzzle_hash_for_pk,
puzzle_hash_for_synthetic_public_key, sign_agg_sig_me, standard_solution_unsafe, ChiaIdentity,
};
#[cfg(test)]
use crate::common::types::Node;
use crate::common::types::{
usize_from_atom, Aggsig, Amount, BrokenOutCoinSpendInfo, CoinCondition, CoinID, CoinSpend,
CoinString, Error, GameID, Hash, IntoErr, PrivateKey, Program, PublicKey, Puzzle, PuzzleHash,
Sha256tree, Spend, SpendRewardResult, ToQuotedProgram,
CoinString, Error, GameID, Hash, IntoErr, Node, PrivateKey, Program, PublicKey, Puzzle,
PuzzleHash, Sha256tree, Spend, SpendRewardResult, Timeout, ToQuotedProgram,
};
use crate::referee::RefereeMaker;

pub struct CoinDataForReward {
coin_string: CoinString,
// parent: CoinID,
// puzzle_hash: PuzzleHash,
// amount: Amount,
}

/// A channel handler runs the game by facilitating the phases of game startup
/// and passing on move information as well as termination to other layers.
///
Expand Down Expand Up @@ -97,6 +89,10 @@ pub struct ChannelHandler {
their_allocated_balance: Amount,

have_potato: bool,
initiated_on_chain: bool,
// Specifies the time lock that should be used in the unroll coin's conditions.
#[allow(dead_code)]
unroll_advance_timeout: Timeout,

cached_last_action: Option<CachedPotatoRegenerateLastHop>,

Expand All @@ -119,6 +115,10 @@ pub struct ChannelHandler {
}

impl ChannelHandler {
pub fn is_initial_potato(&self) -> bool {
self.unroll.coin.started_with_potato
}

pub fn channel_private_key(&self) -> PrivateKey {
self.private_keys.my_channel_coin_private_key.clone()
}
Expand All @@ -143,6 +143,19 @@ impl ChannelHandler {
}
}

pub fn get_unroll_coin(&self) -> &ChannelHandlerUnrollSpendInfo {
&self.unroll
}

fn make_curried_unroll_puzzle<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
) -> Result<NodePtr, Error> {
self.unroll
.coin
.make_curried_unroll_puzzle(env, &self.get_aggregate_unroll_public_key())
}

fn unroll_coin_condition_inputs(
&self,
my_ending_game_value: Amount,
Expand Down Expand Up @@ -260,11 +273,13 @@ impl ChannelHandler {
their_referee_puzzle_hash: initiation.their_referee_puzzle_hash.clone(),
my_out_of_game_balance: initiation.my_contribution.clone(),
their_out_of_game_balance: initiation.their_contribution.clone(),
unroll_advance_timeout: initiation.unroll_advance_timeout.clone(),

my_allocated_balance: Amount::default(),
their_allocated_balance: Amount::default(),

have_potato: initiation.we_start_with_potato,
initiated_on_chain: false,

cached_last_action: None,

Expand Down Expand Up @@ -543,6 +558,8 @@ impl ChannelHandler {
}

self.current_state_number += 1;
debug!("current state number now {}", self.current_state_number);
debug!("test_unroll updated {:?}", test_unroll.outcome);
self.timeout = Some(ChannelHandlerUnrollSpendInfo {
coin: test_unroll.clone(),
signatures: signatures.clone(),
Expand Down Expand Up @@ -1011,12 +1028,13 @@ impl ChannelHandler {
Ok(rem_conditions)
}

pub fn get_unroll_coin_transaction<R: Rng>(
pub fn get_create_unroll_coin_transaction<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
use_unroll: &ChannelHandlerUnrollSpendInfo,
add_sigs: bool,
) -> Result<ChannelCoinSpentResult, Error> {
assert!(self.timeout.is_some());
let use_unroll = self.get_finished_unroll_coin();

debug!("channel handler at {}", self.current_state_number);

Expand All @@ -1032,13 +1050,21 @@ impl ChannelHandler {
let unroll_puzzle_solution = use_unroll
.coin
.make_unroll_puzzle_solution(env, &self.get_aggregate_unroll_public_key())?;
let solution_program = Program::from_nodeptr(env.allocator, unroll_puzzle_solution)?;

debug!(
"get_unroll_coin_transaction {:?}",
solution_program.to_hex()
);
let mut signature = use_unroll.coin.get_unroll_coin_signature()?;
if add_sigs {
signature += use_unroll.signatures.my_unroll_half_signature_peer.clone();
}
Ok(ChannelCoinSpentResult {
transaction: Spend {
puzzle: Puzzle::from_nodeptr(env.allocator, curried_unroll_puzzle)?,
solution: Program::from_nodeptr(env.allocator, unroll_puzzle_solution)?,
signature: use_unroll.coin.get_unroll_coin_signature()?
+ use_unroll.signatures.my_unroll_half_signature_peer.clone(),
solution: solution_program,
signature,
},
timeout: false,
games_canceled: self.get_just_created_games(),
Expand Down Expand Up @@ -1087,37 +1113,28 @@ impl ChannelHandler {
pub fn channel_coin_spent<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
myself: bool,
conditions: NodePtr,
) -> Result<ChannelCoinSpentResult, Error> {
let rem_conditions = self.break_out_conditions_for_spent_coin(env, conditions)?;
let full_coin = self.get_finished_unroll_coin();
let full_coin = self.get_unroll_coin();

let state_number = usize_from_atom(&rem_conditions[0])
.ok_or_else(|| Error::StrErr("Unconvertible state number".to_string()))?;

let our_parity = self.unroll.coin.state_number & 1;
let our_parity = full_coin.coin.state_number & 1;
let their_parity = state_number & 1;

debug!(
"CHANNEL COIN SPENT: my state {} coin state {} channel coin state {state_number}",
self.current_state_number, full_coin.coin.state_number
"{} CHANNEL COIN SPENT: myself {myself} initiated {} my state {} coin state {} channel coin state {state_number}",
self.unroll.coin.started_with_potato,
self.initiated_on_chain,
self.current_state_number,
full_coin.coin.state_number
);

match state_number.cmp(&self.current_state_number) {
Ordering::Greater => Err(Error::StrErr(format!(
"Reply from the future onchain {} (me {}) vs {}",
state_number, self.current_state_number, self.unroll.coin.state_number
))),
Ordering::Less => {
if our_parity == their_parity {
return Err(Error::StrErr(
"We're superceding ourselves from the past?".to_string(),
));
}

self.get_unroll_coin_transaction(env)
}
_ => {
match (myself, state_number.cmp(&self.current_state_number)) {
(true, _) | (_, Ordering::Equal) => {
// Timeout
let curried_unroll_puzzle = self
.unroll
Expand All @@ -1138,6 +1155,19 @@ impl ChannelHandler {
games_canceled: self.get_just_created_games(),
})
}
(_, Ordering::Greater) => Err(Error::StrErr(format!(
"Reply from the future onchain {} (me {}) vs {}",
state_number, self.current_state_number, full_coin.coin.state_number
))),
(_, Ordering::Less) => {
if our_parity == their_parity {
return Err(Error::StrErr(
"We're superceding ourselves from the past?".to_string(),
));
}

self.get_create_unroll_coin_transaction(env, full_coin, true)
}
}
}

Expand Down Expand Up @@ -1259,7 +1289,7 @@ impl ChannelHandler {
}
}

pub fn get_new_game_coins_on_chain(
fn get_new_game_coins_on_chain(
&self,
unroll_coin: Option<&CoinID>,
skip_game: &[GameID],
Expand All @@ -1268,6 +1298,63 @@ impl ChannelHandler {
self.compute_game_coin_unroll_data(unroll_coin, skip_game, skip_coin_id, &self.live_games)
}

pub fn get_game_coins<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
) -> Result<Vec<OnChainGameCoin>, Error> {
let state_number = self.unroll.coin.state_number;
// We need the view of the system as of the most recent timeout.
// I made a move, they have the potato, so we need to reconstruct the
// game states from the most recent their turn. If there's a move in the
// state cache then that game uses that puzzle hash and amount, otherwise
// it uses the one from the live game object. Once on chain, we'll need
// the actual puzzle, but that's a problem for a comment other than this
// one.
let unroll_puzzle = self.make_curried_unroll_puzzle(env)?;
let unroll_puzzle_hash = Node(unroll_puzzle).sha256tree(env.allocator);
let parent_coin = self.state_channel_coin().coin_string();
let unroll_coin = CoinString::from_parts(
&parent_coin.to_coin_id(),
&unroll_puzzle_hash,
&(self.my_out_of_game_balance.clone() + self.their_out_of_game_balance.clone()),
);

let disposition =
self.get_cached_disposition_for_spent_result(env, &unroll_coin, state_number)?;
self.get_new_game_coins_on_chain(
Some(&unroll_coin.to_coin_id()),
&disposition
.as_ref()
.map(|d| d.skip_game.clone())
.unwrap_or_default(),
disposition.as_ref().and_then(|d| d.skip_coin_id.as_ref()),
)
}

// Reset our state so that we generate the indicated puzzles from the live games.
pub fn set_state_for_coins<R: Rng>(
&mut self,
env: &mut ChannelHandlerEnv<R>,
coins: &[OnChainGameCoin],
) -> Result<(), Error> {
let mut res = Vec::new();
for game_coin in coins.iter() {
if let Some(live_game) = self
.live_games
.iter_mut()
.find(|f| game_coin.game_id_up == f.game_id)
{
res.append(&mut live_game.set_state_for_coin(env.allocator, game_coin)?);
} else {
// XXX Used to exist, needs ressurection from the cache to potentially replay
// the accept.
todo!();
}
}

Ok(())
}

// what our vanilla coin string is
// return these triplets for all the active games
// (id of game, coin string that's now on chain for it and the referee maker
Expand Down Expand Up @@ -1434,21 +1521,20 @@ impl ChannelHandler {
// Inititate a simple on chain spend.
//
// Currently used for testing but might be used elsewhere.
#[cfg(test)]
pub fn get_unroll_target<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
) -> Result<(usize, PuzzleHash, Amount, Amount), Error> {
let use_unroll = self.get_finished_unroll_coin();
use_unroll: &ChannelHandlerUnrollSpendInfo,
) -> Result<UnrollTarget, Error> {
let curried_unroll_puzzle = use_unroll
.coin
.make_curried_unroll_puzzle(env, &self.get_aggregate_unroll_public_key())?;

Ok((
use_unroll.coin.state_number,
Node(curried_unroll_puzzle).sha256tree(&mut env.allocator),
self.my_out_of_game_balance.clone(),
self.their_out_of_game_balance.clone(),
))
Ok(UnrollTarget {
state_number: use_unroll.coin.state_number,
unroll_puzzle_hash: Node(curried_unroll_puzzle).sha256tree(env.allocator),
my_amount: self.my_out_of_game_balance.clone(),
their_amount: self.their_out_of_game_balance.clone(),
})
}
}
4 changes: 3 additions & 1 deletion src/channel_handler/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::common::standard_coin::{
get_standard_coin_puzzle, private_to_public_key, puzzle_for_pk, read_hex_puzzle,
};
use crate::common::types::{
AllocEncoder, Amount, CoinID, Error, GameID, Hash, Puzzle, PuzzleHash, Sha256tree,
AllocEncoder, Amount, CoinID, Error, GameID, Hash, Puzzle, PuzzleHash, Sha256tree, Timeout,
};

pub struct ChannelHandlerParty {
Expand Down Expand Up @@ -52,6 +52,7 @@ impl ChannelHandlerGame {
game_id: GameID,
launcher_coin_id: &CoinID,
contributions: &[Amount; 2],
unroll_advance_timeout: Timeout,
) -> Result<ChannelHandlerGame, Error> {
let private_keys: [ChannelHandlerPrivateKeys; 2] = env.rng.gen();

Expand Down Expand Up @@ -81,6 +82,7 @@ impl ChannelHandlerGame {
their_referee_puzzle_hash: referees[id ^ 1].1.clone(),
my_contribution: contributions[id].clone(),
their_contribution: contributions[id ^ 1].clone(),
unroll_advance_timeout: unroll_advance_timeout.clone(),
};

ChannelHandlerParty::new(
Expand Down
Loading
Loading