Skip to content

Commit 2c8c533

Browse files
committed
Pull in a way of trunking the mutables down the stack so we can pass on mutable updates via notifications in the tests. May make this trait an exported personality of PeerEnv
1 parent 666ceab commit 2c8c533

File tree

3 files changed

+231
-73
lines changed

3 files changed

+231
-73
lines changed

src/common/types.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,9 @@ pub struct SpendRewardResult {
930930
pub result_coin_string_up: CoinString,
931931
}
932932

933-
pub struct SpendBundle {}
933+
pub struct SpendBundle {
934+
pub spends: Vec<CoinSpend>
935+
}
934936

935937
pub fn usize_from_atom(a: &[u8]) -> Option<usize> {
936938
let bi = BigInt::from_bytes_be(Sign::Plus, a);

src/outside.rs

+190-54
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::collections::VecDeque;
22

3+
#[cfg(test)]
4+
use clvm_traits::ToClvm;
35
use clvmr::NodePtr;
46
use rand::Rng;
57
use serde::{Deserialize, Serialize};
@@ -9,11 +11,17 @@ use crate::channel_handler::types::{
911
ChannelHandlerPrivateKeys, PotatoSignatures, ReadableMove,
1012
};
1113
use crate::channel_handler::ChannelHandler;
14+
#[cfg(test)]
15+
use crate::common::constants::CREATE_COIN;
1216
use crate::common::standard_coin::{private_to_public_key, puzzle_hash_for_pk};
17+
#[cfg(test)]
18+
use crate::common::standard_coin::standard_solution_partial;
1319
use crate::common::types::{
1420
Aggsig, Amount, CoinID, CoinString, Error, GameID, IntoErr, PublicKey, PuzzleHash, Spend,
1521
SpendBundle, Timeout,
1622
};
23+
#[cfg(test)]
24+
use crate::common::types::{CoinSpend, Program};
1725

1826
struct LocalGameStart {}
1927

@@ -48,7 +56,11 @@ struct RemoteGameStart {}
4856
/// to not take place in the potato handler. The injected wallet bootstrap
4957
/// dependency must be stateful enough that it can cope with receiving a partly
5058
/// funded offer spend bundle and fully fund it if needed.
51-
pub trait BootstrapTowardGame {
59+
pub trait BootstrapTowardGame<
60+
G: ToLocalUI + BootstrapTowardWallet + WalletSpendInterface + PacketSender,
61+
R: Rng,
62+
>
63+
{
5264
/// Gives a partly signed offer to the wallet bootstrap.
5365
///
5466
/// Intended use: channel_puzzle_hash delivers the desired puzzle hash and this
@@ -85,7 +97,8 @@ pub trait BootstrapTowardGame {
8597
///
8698
/// Only alice sends this spend bundle in message E, but only after receiving
8799
/// message D.
88-
fn channel_offer(&mut self, bundle: &SpendBundle) -> Result<(), Error>;
100+
fn channel_offer(&mut self, penv: &mut PeerEnv<G, R>, bundle: SpendBundle)
101+
-> Result<(), Error>;
89102

90103
/// Gives the fully signed offer to the wallet bootstrap.
91104
/// Causes bob to send this spend bundle down the wire to the other peer.
@@ -106,7 +119,11 @@ pub trait BootstrapTowardGame {
106119
///
107120
/// Both alice and bob, upon knowing the full channel coin id, use the more
108121
/// general wallet interface to register for notifications of the channel coin.
109-
fn channel_transaction_completion(&mut self, bundle: &SpendBundle) -> Result<(), Error>;
122+
fn channel_transaction_completion(
123+
&mut self,
124+
penv: &mut PeerEnv<G, R>,
125+
bundle: &SpendBundle,
126+
) -> Result<(), Error>;
110127
}
111128

112129
/// Async interface implemented by Peer to receive notifications about wallet
@@ -236,46 +253,104 @@ pub enum PeerMessage {
236253
RequestPotato,
237254
}
238255

256+
pub struct HandshakeStepInfo {
257+
#[allow(dead_code)]
258+
pub first_player_hs_info: HandshakeA,
259+
#[allow(dead_code)]
260+
pub second_player_hs_info: HandshakeB,
261+
}
262+
263+
pub struct HandshakeStepWithLauncher {
264+
#[allow(dead_code)]
265+
pub info: HandshakeStepInfo,
266+
#[allow(dead_code)]
267+
pub launcher: CoinString,
268+
}
269+
270+
pub struct HandshakeStepWithSpend {
271+
#[allow(dead_code)]
272+
pub info: HandshakeStepInfo,
273+
#[allow(dead_code)]
274+
pub spend: Spend,
275+
}
276+
239277
pub enum HandshakeState {
240278
PreInit,
241279
StepA,
242-
StepB(CoinString, HandshakeA),
243-
StepC {
244-
first_player_hs_info: HandshakeA,
245-
second_player_hs_info: HandshakeB,
246-
},
247-
StepD {
248-
first_player_hs_info: HandshakeA,
249-
second_player_hs_info: HandshakeB,
250-
},
251-
StepE {
252-
first_player_hs_info: HandshakeA,
253-
second_player_hs_info: HandshakeB,
254-
},
255-
StepF {
256-
first_player_hs_info: HandshakeA,
257-
second_player_hs_info: HandshakeB,
258-
channel_initiation_offer: Spend,
259-
},
260-
Finished {
261-
first_player_hs_info: HandshakeA,
262-
second_player_hs_info: HandshakeB,
263-
channel_initiation_transaction: Spend,
264-
},
280+
StepB(CoinString, Box<HandshakeA>),
281+
StepC(Box<HandshakeStepInfo>),
282+
StepD(Box<HandshakeStepWithLauncher>),
283+
StepE(Box<HandshakeStepInfo>),
284+
StepF(Box<HandshakeStepWithSpend>),
285+
Finished(Box<HandshakeStepInfo>),
265286
}
266287

267288
pub trait PacketSender {
268289
fn send_message(&mut self, msg: &PeerMessage) -> Result<(), Error>;
269290
}
270291

271-
pub struct PeerEnv<'a, G, R>
292+
pub struct PeerEnv<'inputs, G, R>
272293
where
273294
G: ToLocalUI + WalletSpendInterface + BootstrapTowardWallet + PacketSender,
274295
R: Rng,
275296
{
276-
pub env: &'a mut ChannelHandlerEnv<'a, R>,
297+
pub env: &'inputs mut ChannelHandlerEnv<'inputs, R>,
277298

278-
pub system_interface: &'a mut G,
299+
pub system_interface: &'inputs mut G,
300+
}
301+
302+
// This is test infrastructure, so it makes assumptions about the environment the
303+
// test is running in.
304+
#[cfg(test)]
305+
impl<'inputs, G, R> PeerEnv<'inputs, G, R>
306+
where
307+
G: ToLocalUI + WalletSpendInterface + BootstrapTowardWallet + PacketSender,
308+
R: Rng,
309+
{
310+
#[cfg(test)]
311+
pub fn test_handle_received_channel_puzzle_hash(
312+
&mut self,
313+
peer: &mut PotatoHandler,
314+
parent: &CoinString,
315+
channel_handler_puzzle_hash: &PuzzleHash,
316+
) -> Result<(), Error> {
317+
let ch = peer.channel_handler()?;
318+
let channel_coin = ch.state_channel_coin();
319+
let channel_coin_amt =
320+
if let Some((_, _, amt)) = channel_coin.coin_string().to_parts() {
321+
amt
322+
} else {
323+
return Err(Error::StrErr("no channel coin".to_string()));
324+
};
325+
326+
let public_key = private_to_public_key(&ch.channel_private_key());
327+
let conditions_clvm = [
328+
(CREATE_COIN, (channel_handler_puzzle_hash.clone(), (channel_coin_amt, ())))
329+
].to_clvm(self.env.allocator).into_gen()?;
330+
let spend = standard_solution_partial(
331+
self.env.allocator,
332+
&ch.channel_private_key(),
333+
&parent.to_coin_id(),
334+
conditions_clvm,
335+
&public_key,
336+
&self.env.agg_sig_me_additional_data,
337+
false,
338+
)?;
339+
let spend_solution_program = Program::from_nodeptr(
340+
&mut self.env.allocator, spend.solution.clone()
341+
)?;
342+
343+
peer.channel_offer(self, SpendBundle {
344+
spends: vec![CoinSpend {
345+
coin: parent.clone(),
346+
bundle: Spend {
347+
puzzle: self.env.standard_puzzle.clone(),
348+
solution: spend_solution_program,
349+
signature: spend.signature.clone()
350+
}
351+
}]
352+
})
353+
}
279354
}
280355

281356
/// Handle potato in flight when I request potato:
@@ -303,6 +378,8 @@ pub struct PotatoHandler {
303378

304379
channel_handler: Option<ChannelHandler>,
305380

381+
channel_initiation_transaction: Option<SpendBundle>,
382+
306383
private_keys: ChannelHandlerPrivateKeys,
307384

308385
my_contribution: Amount,
@@ -352,6 +429,7 @@ impl PotatoHandler {
352429
my_start_queue: VecDeque::default(),
353430

354431
channel_handler: None,
432+
channel_initiation_transaction: None,
355433

356434
private_keys,
357435
my_contribution,
@@ -360,6 +438,14 @@ impl PotatoHandler {
360438
}
361439
}
362440

441+
pub fn channel_handler(&self) -> Result<&ChannelHandler, Error> {
442+
if let Some(ch) = &self.channel_handler {
443+
Ok(ch)
444+
} else {
445+
Err(Error::StrErr("no channel handler".to_string()))
446+
}
447+
}
448+
363449
fn channel_handler_mut(&mut self) -> Result<&mut ChannelHandler, Error> {
364450
if let Some(ch) = &mut self.channel_handler {
365451
Ok(ch)
@@ -393,7 +479,7 @@ impl PotatoHandler {
393479
reward_puzzle_hash: self.reward_puzzle_hash.clone(),
394480
referee_puzzle_hash,
395481
};
396-
self.handshake_state = HandshakeState::StepB(parent_coin, my_hs_info.clone());
482+
self.handshake_state = HandshakeState::StepB(parent_coin, Box::new(my_hs_info.clone()));
397483
penv.system_interface
398484
.send_message(&PeerMessage::HandshakeA(my_hs_info))?;
399485

@@ -439,6 +525,30 @@ impl PotatoHandler {
439525
Ok(())
440526
}
441527

528+
pub fn try_complete_step_d<G, R: Rng>(&mut self, _penv: &mut PeerEnv<G, R>) -> Result<(), Error>
529+
where
530+
G: ToLocalUI + BootstrapTowardWallet + WalletSpendInterface + PacketSender,
531+
{
532+
if let Some(_spend) = self.channel_initiation_transaction.as_ref() {
533+
todo!();
534+
535+
// self.handshake_state = HandshakeState::StepF {
536+
// first_player_hs_info: first_player_hs_info.clone(),
537+
// second_player_hs_info: second_player_hs_info.clone()
538+
// };
539+
540+
// Outer layer already knows the launcher coin string.
541+
//
542+
// Provide the channel puzzle hash to the full node bootstrap and
543+
// it replies with the channel puzzle hash
544+
// penv.system_interface.send_message(&PeerMessage::HandshakeE {
545+
// bundle:
546+
// })?;
547+
}
548+
549+
Ok(())
550+
}
551+
442552
pub fn received_message<G, R: Rng>(
443553
&mut self,
444554
penv: &mut PeerEnv<G, R>,
@@ -486,6 +596,19 @@ impl PotatoHandler {
486596
let (channel_handler, _init_result) =
487597
ChannelHandler::new(penv.env, self.private_keys.clone(), &init_data)?;
488598

599+
let channel_coin = channel_handler.state_channel_coin();
600+
601+
let channel_puzzle_hash =
602+
if let Some((_, puzzle_hash, _)) = channel_coin.coin_string().to_parts() {
603+
puzzle_hash
604+
} else {
605+
return Err(Error::StrErr("could not understand channel coin parts".to_string()));
606+
};
607+
608+
// Send the boostrap wallet interface the channel puzzle hash to use.
609+
// it will reply at some point with the channel offer.
610+
penv.system_interface.channel_puzzle_hash(&channel_puzzle_hash)?;
611+
489612
// init_result
490613
// pub channel_puzzle_hash_up: PuzzleHash,
491614
// pub my_initial_channel_half_signature_peer: Aggsig,
@@ -507,20 +630,17 @@ impl PotatoHandler {
507630
};
508631

509632
self.channel_handler = Some(channel_handler);
510-
self.handshake_state = HandshakeState::StepC {
633+
self.handshake_state = HandshakeState::StepC(Box::new(HandshakeStepInfo {
511634
first_player_hs_info: msg,
512635
second_player_hs_info: our_handshake_data.clone(),
513-
};
636+
}));
514637

515638
// Factor out to one method.
516639
penv.system_interface
517640
.send_message(&PeerMessage::HandshakeB(our_handshake_data))?;
518641
}
519642

520-
HandshakeState::StepC { ..
521-
// first_player_hs_info,
522-
// second_player_hs_info,
523-
} => {
643+
HandshakeState::StepC(_info) => {
524644
let msg_envelope: PeerMessage =
525645
bson::from_bson(bson::Bson::Document(doc)).into_gen()?;
526646
let nil_msg = if let PeerMessage::Nil(nil_msg) = msg_envelope {
@@ -566,10 +686,13 @@ impl PotatoHandler {
566686
let nil_sigs = channel_handler.send_empty_potato(penv.env)?;
567687

568688
self.channel_handler = Some(channel_handler);
569-
self.handshake_state = HandshakeState::StepD {
570-
first_player_hs_info: my_hs_info.clone(),
571-
second_player_hs_info: msg,
572-
};
689+
self.handshake_state = HandshakeState::StepD(Box::new(HandshakeStepWithLauncher {
690+
info: HandshakeStepInfo {
691+
first_player_hs_info: *my_hs_info.clone(),
692+
second_player_hs_info: msg,
693+
},
694+
launcher: parent_coin.clone()
695+
}));
573696

574697
penv.system_interface
575698
.send_message(&PeerMessage::Nil(nil_sigs))?;
@@ -580,20 +703,7 @@ impl PotatoHandler {
580703
// _second_player_hs_info,
581704
} => {
582705
self.pass_on_channel_handler_message(penv, msg)?;
583-
584-
todo!();
585-
// self.handshake_state = HandshakeState::StepF {
586-
// first_player_hs_info: first_player_hs_info.clone(),
587-
// second_player_hs_info: second_player_hs_info.clone()
588-
// };
589-
590-
// Outer layer already knows the launcher coin string.
591-
//
592-
// Provide the channel puzzle hash to the full node bootstrap and
593-
// it replies with the channel puzzle hash
594-
// penv.system_interface.send_message(&PeerMessage::HandshakeE {
595-
// bundle:
596-
// })?;
706+
self.try_complete_step_d(penv)?;
597707
}
598708

599709
_ => {
@@ -604,3 +714,29 @@ impl PotatoHandler {
604714
Ok(())
605715
}
606716
}
717+
718+
impl<G: ToLocalUI + BootstrapTowardWallet + WalletSpendInterface + PacketSender, R: Rng>
719+
BootstrapTowardGame<G, R> for PotatoHandler
720+
{
721+
fn channel_offer(
722+
&mut self,
723+
penv: &mut PeerEnv<G, R>,
724+
bundle: SpendBundle,
725+
) -> Result<(), Error> {
726+
self.channel_initiation_transaction = Some(bundle);
727+
728+
if matches!(self.handshake_state, HandshakeState::StepD { .. }) {
729+
self.try_complete_step_d(penv)?;
730+
}
731+
732+
Ok(())
733+
}
734+
735+
fn channel_transaction_completion(
736+
&mut self,
737+
_penv: &mut PeerEnv<G, R>,
738+
_bundle: &SpendBundle,
739+
) -> Result<(), Error> {
740+
todo!();
741+
}
742+
}

0 commit comments

Comments
 (0)