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

20240920 accept and shutdown #37

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
51 changes: 29 additions & 22 deletions src/channel_handler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use log::debug;

use rand::prelude::*;

use clvm_tools_rs::classic::clvm_tools::binutils::disassemble;
use clvm_traits::ToClvm;
use clvmr::allocator::NodePtr;

Expand Down Expand Up @@ -912,68 +913,74 @@ impl ChannelHandler {
})
}

/// Uses the channel coin key to post standard format coin generation to the
/// real blockchain via a Spend.
pub fn send_potato_clean_shutdown<R: Rng>(
pub fn state_channel_coin_solution_and_signature<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
conditions: NodePtr,
) -> Result<Spend, Error> {
assert!(self.have_potato);
) -> Result<(NodePtr, Aggsig), Error> {
let aggregate_public_key = self.get_aggregate_channel_public_key();
let spend = self.state_channel_coin();

let channel_coin_spend = spend.get_solution_and_signature_from_conditions(
env,
&self.private_keys.my_channel_coin_private_key,
&aggregate_public_key,
conditions,
)?;

Ok(Spend {
solution: Program::from_nodeptr(env.allocator, channel_coin_spend.solution)?,
signature: channel_coin_spend.signature,
puzzle: puzzle_for_pk(env.allocator, &aggregate_public_key)?,
})
Ok((channel_coin_spend.solution, channel_coin_spend.signature))
}

pub fn state_channel_coin_solution_and_signature<R: Rng>(
/// Uses the channel coin key to post standard format coin generation to the
/// real blockchain via a Spend.
pub fn send_potato_clean_shutdown<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
conditions: NodePtr,
) -> Result<(NodePtr, Aggsig), Error> {
) -> Result<Spend, Error> {
debug!("SEND_POTATO_CLEAN_SHUTDOWN");
assert!(self.have_potato);
let aggregate_public_key = self.get_aggregate_channel_public_key();
let spend = self.state_channel_coin();

let channel_coin_spend = spend.get_solution_and_signature_from_conditions(
env,
&self.private_keys.my_channel_coin_private_key,
&aggregate_public_key,
conditions,
)?;

Ok((channel_coin_spend.solution, channel_coin_spend.signature))
debug!(
"send_potato_clean_shutdown {}",
disassemble(env.allocator.allocator(), channel_coin_spend.solution, None)
);

Ok(Spend {
solution: Program::from_nodeptr(env.allocator, channel_coin_spend.solution)?,
signature: channel_coin_spend.signature,
puzzle: puzzle_for_pk(env.allocator, &aggregate_public_key)?,
})
}

pub fn received_potato_clean_shutdown<R: Rng>(
&self,
env: &mut ChannelHandlerEnv<R>,
their_channel_half_signature: &Aggsig,
conditions: NodePtr,
) -> Result<Spend, Error> {
let aggregate_public_key = self.get_aggregate_channel_public_key();

) -> Result<BrokenOutCoinSpendInfo, Error> {
debug!("RECEIVED_POTATO_CLEAN_SHUTDOWN");
assert!(!self.have_potato);
let channel_spend = self.verify_channel_coin_from_peer_signatures(
env,
their_channel_half_signature,
conditions,
)?;

Ok(Spend {
solution: Program::from_nodeptr(env.allocator, channel_spend.solution)?,
signature: channel_spend.signature,
puzzle: puzzle_for_pk(env.allocator, &aggregate_public_key)?,
})
debug!(
"received_potato_clean_shutdown {}",
disassemble(env.allocator.allocator(), channel_spend.solution, None)
);

Ok(channel_spend)
}

fn break_out_conditions_for_spent_coin<R: Rng>(
Expand Down
3 changes: 3 additions & 0 deletions src/common/standard_coin.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fs::read_to_string;

use log::debug;
use num_bigint::{BigInt, Sign};

use chia_bls;
Expand Down Expand Up @@ -430,6 +431,7 @@ pub fn standard_solution_partial(
let quoted_conds = conditions.to_quoted_program(allocator)?;
let quoted_conds_hash = quoted_conds.sha256tree(allocator);
let solution = solution_for_conditions(allocator, conditions)?;
debug!("standard signing with parent coin {parent_coin:?}");
let coin_agg_sig_me_message = agg_sig_me_message(
quoted_conds_hash.bytes(),
parent_coin,
Expand All @@ -454,6 +456,7 @@ pub fn standard_solution_partial(
for cond in conds.iter() {
match cond {
CoinCondition::CreateCoin(_, _) => {
debug!("adding signature based on create coin: {aggregate_public_key:?} {coin_agg_sig_me_message:?}");
add_signature(
&mut aggregated_signature,
if partial {
Expand Down
28 changes: 27 additions & 1 deletion src/tests/calpoker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use clvm_traits::{ClvmEncoder, ToClvm};

use crate::channel_handler::game::Game;
use crate::channel_handler::types::ReadableMove;
use crate::common::types::{AllocEncoder, Amount, Error, GameID, Hash, Sha256Input};
use crate::common::constants::CREATE_COIN;
use crate::common::standard_coin::ChiaIdentity;
use crate::common::types::{AllocEncoder, Amount, Error, GameID, Hash, PrivateKey, Sha256Input};
use crate::games::calpoker::decode_calpoker_readable;
use crate::games::calpoker::decode_readable_card_choices;
use crate::games::calpoker::make_cards;
Expand Down Expand Up @@ -235,6 +237,30 @@ fn test_play_calpoker_on_chain_after_2_moves_p1() {
debug!("play_result {test4:?}");
}

#[cfg(feature = "sim-tests")]
#[test]
fn test_play_calpoker_end_game_reward() {
let mut allocator = AllocEncoder::new();

let seed: [u8; 32] = [0; 32];
let mut rng = ChaCha8Rng::from_seed(seed);
let output_private_key: PrivateKey = rng.gen();
let output_identity = ChiaIdentity::new(&mut allocator, output_private_key).unwrap();

let mut moves = test_moves_1(&mut allocator).to_vec();
moves.push(GameAction::Accept(1));
let win_conditions = [(
CREATE_COIN,
(output_identity.puzzle_hash.clone(), (Amount::new(200), ())),
)]
.to_clvm(&mut allocator)
.unwrap();
moves.push(GameAction::Shutdown(0, win_conditions));

debug!("running moves {moves:?}");
let _game_action_results = run_calpoker_play_test(&mut allocator, &moves).expect("should work");
}

// Bram: slashing tests
//
// I think this is a decent list of slashing tests: Alice attempts to give
Expand Down
9 changes: 8 additions & 1 deletion src/tests/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ use crate::channel_handler::types::{ChannelHandlerEnv, PrintableGameStartInfo};
use crate::common::standard_coin::{
private_to_public_key, puzzle_hash_for_synthetic_public_key, ChiaIdentity,
};
use crate::common::types::Amount;
#[cfg(feature = "sim-tests")]
use crate::common::types::{Amount, CoinString, Error, IntoErr, Timeout};
use crate::common::types::{CoinString, Error, IntoErr, Timeout};

#[cfg(feature = "sim-tests")]
use crate::simulator::Simulator;
Expand All @@ -35,6 +36,10 @@ pub enum GameAction {
FakeMove(usize, NodePtr, Vec<u8>),
/// Go on chain
GoOnChain(usize),
/// Accept
Accept(usize),
/// Shut down
Shutdown(usize, NodePtr),
}

impl GameAction {
Expand All @@ -53,6 +58,8 @@ pub enum GameActionResult {
MoveResult(NodePtr, Vec<u8>, Option<ReadableMove>, Hash),
BrokenMove,
MoveToOnChain,
Accepted(Amount),
Shutdown,
}

#[cfg(feature = "sim-tests")]
Expand Down
82 changes: 82 additions & 0 deletions src/tests/simenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,88 @@ impl<'a, R: Rng> SimulatorEnvironment<'a, R> {
self.on_chain = OnChainState::OnChain(game_coins);
Ok(GameActionResult::MoveToOnChain)
}
GameAction::Accept(player) => {
let game_id = self.parties.game_id.clone();
let (signatures, amount) = self
.parties
.player(*player)
.ch
.send_potato_accept(&mut self.env, &game_id)?;

let spend = self.parties.player(*player ^ 1).ch.received_potato_accept(
&mut self.env,
&signatures,
&game_id,
)?;

self.parties
.update_channel_coin_after_receive(*player ^ 1, &spend)?;

Ok(GameActionResult::Accepted(amount))
}
GameAction::Shutdown(player, target_conditions) => {
let spend = self
.parties
.player(*player)
.ch
.send_potato_clean_shutdown(&mut self.env, *target_conditions)?;

let full_spend = self
.parties
.player(*player ^ 1)
.ch
.received_potato_clean_shutdown(
&mut self.env,
&spend.signature,
*target_conditions,
)?;

// The shutdown gives a spend, which we need to do here.
let channel_coin = self
.parties
.player(*player)
.ch
.state_channel_coin()
.coin_string()
.clone();

let full_spend_sol = full_spend.solution;
debug!(
"solution in full spend: {}",
disassemble(self.env.allocator.allocator(), full_spend_sol, None)
);

let channel_puzzle_public_key = self
.parties
.player(*player)
.ch
.get_aggregate_channel_public_key();
let puzzle = puzzle_for_synthetic_public_key(
self.env.allocator,
&self.env.standard_puzzle,
&channel_puzzle_public_key,
)?;
let solution = Program::from_nodeptr(self.env.allocator, full_spend.solution)?;
let included = self
.simulator
.push_tx(
self.env.allocator,
&[CoinSpend {
coin: channel_coin,
bundle: Spend {
solution,
puzzle,
signature: full_spend.signature.clone(),
},
}],
)
.unwrap();

debug!("included {included:?}");
assert_eq!(included.code, 1);

Ok(GameActionResult::Shutdown)
}
_ => {
todo!();
}
Expand Down
Loading