1
1
use std:: collections:: VecDeque ;
2
2
3
+ #[ cfg( test) ]
4
+ use clvm_traits:: ToClvm ;
3
5
use clvmr:: NodePtr ;
4
6
use rand:: Rng ;
5
7
use serde:: { Deserialize , Serialize } ;
@@ -9,11 +11,17 @@ use crate::channel_handler::types::{
9
11
ChannelHandlerPrivateKeys , PotatoSignatures , ReadableMove ,
10
12
} ;
11
13
use crate :: channel_handler:: ChannelHandler ;
14
+ #[ cfg( test) ]
15
+ use crate :: common:: constants:: CREATE_COIN ;
12
16
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;
13
19
use crate :: common:: types:: {
14
20
Aggsig , Amount , CoinID , CoinString , Error , GameID , IntoErr , PublicKey , PuzzleHash , Spend ,
15
21
SpendBundle , Timeout ,
16
22
} ;
23
+ #[ cfg( test) ]
24
+ use crate :: common:: types:: { CoinSpend , Program } ;
17
25
18
26
struct LocalGameStart { }
19
27
@@ -48,7 +56,11 @@ struct RemoteGameStart {}
48
56
/// to not take place in the potato handler. The injected wallet bootstrap
49
57
/// dependency must be stateful enough that it can cope with receiving a partly
50
58
/// 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
+ {
52
64
/// Gives a partly signed offer to the wallet bootstrap.
53
65
///
54
66
/// Intended use: channel_puzzle_hash delivers the desired puzzle hash and this
@@ -85,7 +97,8 @@ pub trait BootstrapTowardGame {
85
97
///
86
98
/// Only alice sends this spend bundle in message E, but only after receiving
87
99
/// 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 > ;
89
102
90
103
/// Gives the fully signed offer to the wallet bootstrap.
91
104
/// Causes bob to send this spend bundle down the wire to the other peer.
@@ -106,7 +119,11 @@ pub trait BootstrapTowardGame {
106
119
///
107
120
/// Both alice and bob, upon knowing the full channel coin id, use the more
108
121
/// 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 > ;
110
127
}
111
128
112
129
/// Async interface implemented by Peer to receive notifications about wallet
@@ -236,46 +253,104 @@ pub enum PeerMessage {
236
253
RequestPotato ,
237
254
}
238
255
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
+
239
277
pub enum HandshakeState {
240
278
PreInit ,
241
279
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 > ) ,
265
286
}
266
287
267
288
pub trait PacketSender {
268
289
fn send_message ( & mut self , msg : & PeerMessage ) -> Result < ( ) , Error > ;
269
290
}
270
291
271
- pub struct PeerEnv < ' a , G , R >
292
+ pub struct PeerEnv < ' inputs , G , R >
272
293
where
273
294
G : ToLocalUI + WalletSpendInterface + BootstrapTowardWallet + PacketSender ,
274
295
R : Rng ,
275
296
{
276
- pub env : & ' a mut ChannelHandlerEnv < ' a , R > ,
297
+ pub env : & ' inputs mut ChannelHandlerEnv < ' inputs , R > ,
277
298
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
+ }
279
354
}
280
355
281
356
/// Handle potato in flight when I request potato:
@@ -303,6 +378,8 @@ pub struct PotatoHandler {
303
378
304
379
channel_handler : Option < ChannelHandler > ,
305
380
381
+ channel_initiation_transaction : Option < SpendBundle > ,
382
+
306
383
private_keys : ChannelHandlerPrivateKeys ,
307
384
308
385
my_contribution : Amount ,
@@ -352,6 +429,7 @@ impl PotatoHandler {
352
429
my_start_queue : VecDeque :: default ( ) ,
353
430
354
431
channel_handler : None ,
432
+ channel_initiation_transaction : None ,
355
433
356
434
private_keys,
357
435
my_contribution,
@@ -360,6 +438,14 @@ impl PotatoHandler {
360
438
}
361
439
}
362
440
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
+
363
449
fn channel_handler_mut ( & mut self ) -> Result < & mut ChannelHandler , Error > {
364
450
if let Some ( ch) = & mut self . channel_handler {
365
451
Ok ( ch)
@@ -393,7 +479,7 @@ impl PotatoHandler {
393
479
reward_puzzle_hash : self . reward_puzzle_hash . clone ( ) ,
394
480
referee_puzzle_hash,
395
481
} ;
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 ( ) ) ) ;
397
483
penv. system_interface
398
484
. send_message ( & PeerMessage :: HandshakeA ( my_hs_info) ) ?;
399
485
@@ -439,6 +525,30 @@ impl PotatoHandler {
439
525
Ok ( ( ) )
440
526
}
441
527
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
+
442
552
pub fn received_message < G , R : Rng > (
443
553
& mut self ,
444
554
penv : & mut PeerEnv < G , R > ,
@@ -486,6 +596,19 @@ impl PotatoHandler {
486
596
let ( channel_handler, _init_result) =
487
597
ChannelHandler :: new ( penv. env , self . private_keys . clone ( ) , & init_data) ?;
488
598
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
+
489
612
// init_result
490
613
// pub channel_puzzle_hash_up: PuzzleHash,
491
614
// pub my_initial_channel_half_signature_peer: Aggsig,
@@ -507,20 +630,17 @@ impl PotatoHandler {
507
630
} ;
508
631
509
632
self . channel_handler = Some ( channel_handler) ;
510
- self . handshake_state = HandshakeState :: StepC {
633
+ self . handshake_state = HandshakeState :: StepC ( Box :: new ( HandshakeStepInfo {
511
634
first_player_hs_info : msg,
512
635
second_player_hs_info : our_handshake_data. clone ( ) ,
513
- } ;
636
+ } ) ) ;
514
637
515
638
// Factor out to one method.
516
639
penv. system_interface
517
640
. send_message ( & PeerMessage :: HandshakeB ( our_handshake_data) ) ?;
518
641
}
519
642
520
- HandshakeState :: StepC { ..
521
- // first_player_hs_info,
522
- // second_player_hs_info,
523
- } => {
643
+ HandshakeState :: StepC ( _info) => {
524
644
let msg_envelope: PeerMessage =
525
645
bson:: from_bson ( bson:: Bson :: Document ( doc) ) . into_gen ( ) ?;
526
646
let nil_msg = if let PeerMessage :: Nil ( nil_msg) = msg_envelope {
@@ -566,10 +686,13 @@ impl PotatoHandler {
566
686
let nil_sigs = channel_handler. send_empty_potato ( penv. env ) ?;
567
687
568
688
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
+ } ) ) ;
573
696
574
697
penv. system_interface
575
698
. send_message ( & PeerMessage :: Nil ( nil_sigs) ) ?;
@@ -580,20 +703,7 @@ impl PotatoHandler {
580
703
// _second_player_hs_info,
581
704
} => {
582
705
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) ?;
597
707
}
598
708
599
709
_ => {
@@ -604,3 +714,29 @@ impl PotatoHandler {
604
714
Ok ( ( ) )
605
715
}
606
716
}
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