1
1
extern crate core;
2
2
3
- use std:: { fs, io, path:: PathBuf } ;
4
- use std:: io:: { Cursor , IsTerminal } ;
3
+ use std:: {
4
+ fs, io,
5
+ io:: { Cursor , IsTerminal } ,
6
+ path:: PathBuf ,
7
+ } ;
8
+
5
9
use anyhow:: anyhow;
6
10
use base64:: Engine ;
7
11
use clap:: { Parser , Subcommand } ;
8
12
use colored:: { Color , Colorize } ;
9
- use domain:: base:: { MessageBuilder , TreeCompressor } ;
10
- use domain:: base:: iana:: Opcode ;
11
- use domain:: zonefile:: inplace:: { Entry , Zonefile } ;
13
+ use domain:: {
14
+ base:: { iana:: Opcode , MessageBuilder , TreeCompressor } ,
15
+ zonefile:: inplace:: { Entry , Zonefile } ,
16
+ } ;
12
17
use jsonrpsee:: {
13
18
core:: { client:: Error , ClientError } ,
14
19
http_client:: { HttpClient , HttpClientBuilder } ,
15
20
} ;
16
21
use serde:: { Deserialize , Serialize } ;
17
- use spaces_client:: { config:: { default_spaces_rpc_port, ExtendedNetwork } , serialize_base64, deserialize_base64, format:: {
18
- print_error_rpc_response, print_list_bidouts, print_list_spaces_response,
19
- print_list_transactions, print_list_unspent, print_server_info,
20
- print_wallet_balance_response, print_wallet_info, print_wallet_response, Format ,
21
- } , rpc:: {
22
- BidParams , ExecuteParams , OpenParams , RegisterParams , RpcClient , RpcWalletRequest ,
23
- RpcWalletTxBuilder , SendCoinsParams , TransferSpacesParams ,
24
- } , wallets:: { AddressKind , WalletResponse } } ;
25
- use spaces_protocol:: { bitcoin:: { Amount , FeeRate , OutPoint , Txid } } ;
26
- use spaces_wallet:: { bitcoin:: secp256k1:: schnorr:: Signature , export:: WalletExport , Listing } ;
27
- use spaces_wallet:: nostr:: { NostrEvent , NostrTag } ;
22
+ use spaces_client:: {
23
+ config:: { default_spaces_rpc_port, ExtendedNetwork } ,
24
+ deserialize_base64,
25
+ format:: {
26
+ print_error_rpc_response, print_list_bidouts, print_list_spaces_response,
27
+ print_list_transactions, print_list_unspent, print_server_info,
28
+ print_wallet_balance_response, print_wallet_info, print_wallet_response, Format ,
29
+ } ,
30
+ rpc:: {
31
+ BidParams , ExecuteParams , OpenParams , RegisterParams , RpcClient , RpcWalletRequest ,
32
+ RpcWalletTxBuilder , SendCoinsParams , TransferSpacesParams ,
33
+ } ,
34
+ serialize_base64,
35
+ wallets:: { AddressKind , WalletResponse } ,
36
+ } ;
37
+ use spaces_protocol:: bitcoin:: { Amount , FeeRate , OutPoint , Txid } ;
38
+ use spaces_wallet:: {
39
+ bitcoin:: secp256k1:: schnorr:: Signature ,
40
+ export:: WalletExport ,
41
+ nostr:: { NostrEvent , NostrTag } ,
42
+ Listing ,
43
+ } ;
28
44
29
45
#[ derive( Parser , Debug ) ]
30
46
#[ command( version, about, long_about = None ) ]
@@ -357,7 +373,7 @@ struct Base64Bytes(
357
373
serialize_with = "serialize_base64" ,
358
374
deserialize_with = "deserialize_base64"
359
375
) ]
360
- Vec < u8 >
376
+ Vec < u8 > ,
361
377
) ;
362
378
363
379
impl SpaceCli {
@@ -383,14 +399,16 @@ impl SpaceCli {
383
399
) )
384
400
}
385
401
386
- async fn sign_event ( & self , space : String , event : NostrEvent , anchor : bool , most_recent : bool ) -> Result < NostrEvent , ClientError > {
402
+ async fn sign_event (
403
+ & self ,
404
+ space : String ,
405
+ event : NostrEvent ,
406
+ anchor : bool ,
407
+ most_recent : bool ,
408
+ ) -> Result < NostrEvent , ClientError > {
387
409
let mut result = self
388
410
. client
389
- . wallet_sign_event (
390
- & self . wallet ,
391
- & space,
392
- event,
393
- )
411
+ . wallet_sign_event ( & self . wallet , & space, event)
394
412
. await ?;
395
413
396
414
if anchor {
@@ -399,21 +417,45 @@ impl SpaceCli {
399
417
400
418
Ok ( result)
401
419
}
402
- async fn add_anchor ( & self , mut event : NostrEvent , most_recent : bool ) -> Result < NostrEvent , ClientError > {
420
+ async fn add_anchor (
421
+ & self ,
422
+ mut event : NostrEvent ,
423
+ most_recent : bool ,
424
+ ) -> Result < NostrEvent , ClientError > {
403
425
let space = match event. space ( ) {
404
- None => return Err ( ClientError :: Custom ( "A space tag is required to add an anchor" . to_string ( ) ) ) ,
405
- Some ( space) => space
426
+ None => {
427
+ return Err ( ClientError :: Custom (
428
+ "A space tag is required to add an anchor" . to_string ( ) ,
429
+ ) )
430
+ }
431
+ Some ( space) => space,
406
432
} ;
407
433
408
- let spaceout = self . client . get_space ( & space) . await
434
+ let spaceout = self
435
+ . client
436
+ . get_space ( & space)
437
+ . await
409
438
. map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?
410
- . ok_or ( ClientError :: Custom ( format ! ( "Space not found \" {}\" " , space) ) ) ?;
411
-
412
- event. proof = Some ( base64:: prelude:: BASE64_STANDARD . encode ( self . client . prove_spaceout ( OutPoint {
413
- txid : spaceout. txid ,
414
- vout : spaceout. spaceout . n as _ ,
415
- } , Some ( most_recent) ) . await . map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?
416
- . proof ) ) ;
439
+ . ok_or ( ClientError :: Custom ( format ! (
440
+ "Space not found \" {}\" " ,
441
+ space
442
+ ) ) ) ?;
443
+
444
+ event. proof = Some (
445
+ base64:: prelude:: BASE64_STANDARD . encode (
446
+ self . client
447
+ . prove_spaceout (
448
+ OutPoint {
449
+ txid : spaceout. txid ,
450
+ vout : spaceout. spaceout . n as _ ,
451
+ } ,
452
+ Some ( most_recent) ,
453
+ )
454
+ . await
455
+ . map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?
456
+ . proof ,
457
+ ) ,
458
+ ) ;
417
459
418
460
Ok ( event)
419
461
}
@@ -510,10 +552,7 @@ async fn main() -> anyhow::Result<()> {
510
552
Ok ( ( ) )
511
553
}
512
554
513
- async fn handle_commands (
514
- cli : & SpaceCli ,
515
- command : Commands ,
516
- ) -> Result < ( ) , ClientError > {
555
+ async fn handle_commands ( cli : & SpaceCli , command : Commands ) -> Result < ( ) , ClientError > {
517
556
match command {
518
557
Commands :: GetRollout {
519
558
target_interval : target,
@@ -575,7 +614,7 @@ async fn handle_commands(
575
614
fee_rate,
576
615
false ,
577
616
)
578
- . await ?
617
+ . await ?
579
618
}
580
619
Commands :: Bid {
581
620
space,
@@ -592,7 +631,7 @@ async fn handle_commands(
592
631
fee_rate,
593
632
confirmed_only,
594
633
)
595
- . await ?
634
+ . await ?
596
635
}
597
636
Commands :: CreateBidOuts { pairs, fee_rate } => {
598
637
cli. send_request ( None , Some ( pairs) , fee_rate, false ) . await ?
@@ -611,7 +650,7 @@ async fn handle_commands(
611
650
fee_rate,
612
651
false ,
613
652
)
614
- . await ?
653
+ . await ?
615
654
}
616
655
Commands :: Renew { spaces, fee_rate } => {
617
656
let spaces: Vec < _ > = spaces. into_iter ( ) . map ( |s| normalize_space ( & s) ) . collect ( ) ;
@@ -624,7 +663,7 @@ async fn handle_commands(
624
663
fee_rate,
625
664
false ,
626
665
)
627
- . await ?
666
+ . await ?
628
667
}
629
668
Commands :: Transfer {
630
669
spaces,
@@ -641,7 +680,7 @@ async fn handle_commands(
641
680
fee_rate,
642
681
false ,
643
682
)
644
- . await ?
683
+ . await ?
645
684
}
646
685
Commands :: SendCoins {
647
686
amount,
@@ -657,7 +696,7 @@ async fn handle_commands(
657
696
fee_rate,
658
697
false ,
659
698
)
660
- . await ?
699
+ . await ?
661
700
}
662
701
Commands :: SetRawFallback {
663
702
mut space,
@@ -687,7 +726,7 @@ async fn handle_commands(
687
726
fee_rate,
688
727
false ,
689
728
)
690
- . await ?;
729
+ . await ?;
691
730
}
692
731
Commands :: ListUnspent => {
693
732
let utxos = cli. client . wallet_list_unspent ( & cli. wallet ) . await ?;
@@ -757,7 +796,7 @@ async fn handle_commands(
757
796
} ) ?
758
797
. as_slice ( ) ,
759
798
)
760
- . map_err ( |_| ClientError :: Custom ( "Invalid signature" . to_string ( ) ) ) ?,
799
+ . map_err ( |_| ClientError :: Custom ( "Invalid signature" . to_string ( ) ) ) ?,
761
800
} ;
762
801
let result = cli
763
802
. client
@@ -798,54 +837,70 @@ async fn handle_commands(
798
837
} ) ?
799
838
. as_slice ( ) ,
800
839
)
801
- . map_err ( |_| ClientError :: Custom ( "Invalid signature" . to_string ( ) ) ) ?,
840
+ . map_err ( |_| ClientError :: Custom ( "Invalid signature" . to_string ( ) ) ) ?,
802
841
} ;
803
842
804
843
cli. client . verify_listing ( listing) . await ?;
805
844
println ! ( "{} Listing verified" , "✓" . color( Color :: Green ) ) ;
806
845
}
807
- Commands :: SignEvent { mut space, input, anchor } => {
846
+ Commands :: SignEvent {
847
+ mut space,
848
+ input,
849
+ anchor,
850
+ } => {
808
851
let mut event = read_event ( input)
809
852
. map_err ( |e| ClientError :: Custom ( format ! ( "input error: {}" , e. to_string( ) ) ) ) ?;
810
853
811
854
space = normalize_space ( & space) ;
812
855
match event. space ( ) {
813
- None if anchor => {
814
- event . tags . insert ( 0 , NostrTag ( vec ! [ "space" . to_string ( ) , space . clone ( ) ] ) )
815
- }
856
+ None if anchor => event
857
+ . tags
858
+ . insert ( 0 , NostrTag ( vec ! [ "space" . to_string ( ) , space . clone ( ) ] ) ) ,
816
859
Some ( tag) => {
817
860
if tag != space {
818
- return Err ( ClientError :: Custom (
819
- format ! ( "Expected a space tag with value '{}', got '{}'" , space, tag)
820
- ) ) ;
861
+ return Err ( ClientError :: Custom ( format ! (
862
+ "Expected a space tag with value '{}', got '{}'" ,
863
+ space, tag
864
+ ) ) ) ;
821
865
}
822
866
}
823
867
_ => { }
824
868
} ;
825
869
826
- let result = cli. sign_event ( space, event, anchor, false )
827
- . await ?;
870
+ let result = cli. sign_event ( space, event, anchor, false ) . await ?;
828
871
println ! ( "{}" , serde_json:: to_string_pretty( & result) . expect( "result" ) ) ;
829
872
}
830
- Commands :: SignZone { space, input, skip_anchor } => {
873
+ Commands :: SignZone {
874
+ space,
875
+ input,
876
+ skip_anchor,
877
+ } => {
831
878
let update = encode_dns_update ( & space, input)
832
879
. map_err ( |e| ClientError :: Custom ( format ! ( "Parse error: {}" , e) ) ) ?;
833
880
let result = cli. sign_event ( space, update, !skip_anchor, false ) . await ?;
834
881
835
882
println ! ( "{}" , serde_json:: to_string_pretty( & result) . expect( "result" ) ) ;
836
883
}
837
- Commands :: RefreshAnchor { input, prefer_recent } => {
884
+ Commands :: RefreshAnchor {
885
+ input,
886
+ prefer_recent,
887
+ } => {
838
888
let event = read_event ( input)
839
889
. map_err ( |e| ClientError :: Custom ( format ! ( "input error: {}" , e. to_string( ) ) ) ) ?;
840
890
let space = match event. space ( ) {
841
891
None => {
842
- return Err ( ClientError :: Custom ( "Not a space-anchored event (no space tag)" . to_string ( ) ) )
892
+ return Err ( ClientError :: Custom (
893
+ "Not a space-anchored event (no space tag)" . to_string ( ) ,
894
+ ) )
843
895
}
844
- Some ( space) => space
896
+ Some ( space) => space,
845
897
} ;
846
898
847
- let mut event = cli. client . verify_event ( & space, event)
848
- . await . map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?;
899
+ let mut event = cli
900
+ . client
901
+ . verify_event ( & space, event)
902
+ . await
903
+ . map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?;
849
904
event. proof = None ;
850
905
event = cli. add_anchor ( event, prefer_recent) . await ?;
851
906
@@ -854,8 +909,11 @@ async fn handle_commands(
854
909
Commands :: VerifyEvent { space, input } => {
855
910
let event = read_event ( input)
856
911
. map_err ( |e| ClientError :: Custom ( format ! ( "input error: {}" , e. to_string( ) ) ) ) ?;
857
- let event = cli. client . verify_event ( & space, event)
858
- . await . map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?;
912
+ let event = cli
913
+ . client
914
+ . verify_event ( & space, event)
915
+ . await
916
+ . map_err ( |e| ClientError :: Custom ( e. to_string ( ) ) ) ?;
859
917
860
918
println ! ( "{}" , serde_json:: to_string_pretty( & event) . expect( "result" ) ) ;
861
919
}
@@ -872,33 +930,28 @@ fn encode_dns_update(space: &str, zone_file: Option<PathBuf>) -> anyhow::Result<
872
930
// domain crate panics if zone doesn't end in a new line
873
931
let zone = get_input ( zone_file) ? + "\n " ;
874
932
875
- let mut builder = MessageBuilder :: from_target (
876
- TreeCompressor :: new (
877
- Vec :: new ( )
878
- )
879
- ) ?. authority ( ) ;
933
+ let mut builder = MessageBuilder :: from_target ( TreeCompressor :: new ( Vec :: new ( ) ) ) ?. authority ( ) ;
880
934
881
935
builder. header_mut ( ) . set_opcode ( Opcode :: UPDATE ) ;
882
936
883
937
let mut cursor = Cursor :: new ( zone) ;
884
938
let mut reader = Zonefile :: load ( & mut cursor) ?;
885
939
886
- while let Some ( entry) = reader. next_entry ( )
887
- . or_else ( |e| Err ( anyhow ! ( "Error reading zone entry: {}" , e) ) ) ? {
940
+ while let Some ( entry) = reader
941
+ . next_entry ( )
942
+ . or_else ( |e| Err ( anyhow ! ( "Error reading zone entry: {}" , e) ) ) ?
943
+ {
888
944
if let Entry :: Record ( record) = & entry {
889
945
builder. push ( record) ?;
890
946
}
891
947
}
892
948
893
949
let msg = builder. finish ( ) ;
894
- Ok (
895
- NostrEvent :: new (
896
- 871_222 ,
897
- & base64:: prelude:: BASE64_STANDARD . encode ( msg. as_slice ( ) ) ,
898
- vec ! [
899
- NostrTag ( vec![ "space" . to_string( ) , space. to_string( ) ] )
900
- ] )
901
- )
950
+ Ok ( NostrEvent :: new (
951
+ 871_222 ,
952
+ & base64:: prelude:: BASE64_STANDARD . encode ( msg. as_slice ( ) ) ,
953
+ vec ! [ NostrTag ( vec![ "space" . to_string( ) , space. to_string( ) ] ) ] ,
954
+ ) )
902
955
}
903
956
904
957
fn read_event ( file : Option < PathBuf > ) -> anyhow:: Result < NostrEvent > {
@@ -915,9 +968,7 @@ fn get_input(input: Option<PathBuf>) -> anyhow::Result<String> {
915
968
let input = io:: stdin ( ) ;
916
969
match input. is_terminal ( ) {
917
970
true => return Err ( anyhow ! ( "no input provided: specify file path or stdin" ) ) ,
918
- false => input
919
- . lines ( )
920
- . collect :: < Result < String , _ > > ( ) ?
971
+ false => input. lines ( ) . collect :: < Result < String , _ > > ( ) ?,
921
972
}
922
973
}
923
974
} )
0 commit comments