1
1
use ansi_term:: Color :: { Purple , Red , White , Yellow } ;
2
- use failure:: { bail, Fail } ;
2
+ use failure:: { bail, format_err , Fail } ;
3
3
use itertools:: Itertools ;
4
4
use num_format:: { Locale , ToFormattedString } ;
5
5
use prettytable:: { cell, row, Table } ;
@@ -711,7 +711,6 @@ pub fn master_key_export(
711
711
Ok ( ( ) )
712
712
}
713
713
714
- #[ allow( clippy:: too_many_arguments) ]
715
714
pub fn create_multisig_address (
716
715
n : u8 ,
717
716
m : u8 ,
@@ -736,12 +735,11 @@ pub fn create_multisig_address(
736
735
Item :: Operator ( MyOperator :: CheckMultiSig ) ,
737
736
] ) ;
738
737
739
- let locking_script_hash =
740
- PublicKeyHash :: from_script_bytes ( & witnet_stack:: encode ( redeem_script) ?) ;
738
+ let script_address = PublicKeyHash :: from_script_bytes ( & witnet_stack:: encode ( & redeem_script) ?) ;
741
739
742
740
println ! (
743
- "Sending to {}-of-{} multisig address {} composed of {:?}" ,
744
- m, n, locking_script_hash , pkhs_str
741
+ "Created {}-of-{} multisig address {} composed of {:?}" ,
742
+ m, n, script_address , pkhs_str
745
743
) ;
746
744
747
745
Ok ( ( ) )
@@ -778,7 +776,7 @@ pub fn create_opened_multisig(
778
776
Item :: Value ( MyValue :: Integer ( i128 :: from( n) ) ) ,
779
777
Item :: Operator ( MyOperator :: CheckMultiSig ) ,
780
778
] ) ;
781
- let redeem_script_bytes = witnet_stack:: encode ( redeem_script) ?;
779
+ let redeem_script_bytes = witnet_stack:: encode ( & redeem_script) ?;
782
780
let vt_outputs = vec ! [ ValueTransferOutput {
783
781
pkh: address,
784
782
value,
@@ -807,7 +805,53 @@ pub fn create_opened_multisig(
807
805
let script_tx = parse_response :: < Transaction > ( & response) ?;
808
806
println ! ( "Created transaction:\n {:?}" , script_tx) ;
809
807
let script_transaction_hex = hex:: encode ( script_tx. to_pb_bytes ( ) . unwrap ( ) ) ;
810
- println ! ( "Script bytes: {}" , script_transaction_hex) ;
808
+ println ! ( "Transaction bytes: {}" , script_transaction_hex) ;
809
+ }
810
+ Ok ( ( ) )
811
+ }
812
+
813
+ #[ allow( clippy:: too_many_arguments) ]
814
+ pub fn spend_script_utxo (
815
+ addr : SocketAddr ,
816
+ output_pointer : OutputPointer ,
817
+ value : u64 ,
818
+ fee : u64 ,
819
+ hex : String ,
820
+ change_address : Option < PublicKeyHash > ,
821
+ address : PublicKeyHash ,
822
+ dry_run : bool ,
823
+ ) -> Result < ( ) , failure:: Error > {
824
+ let mut stream = start_client ( addr) ?;
825
+ let redeem_script_bytes = hex:: decode ( hex) ?;
826
+ let vt_outputs = vec ! [ ValueTransferOutput {
827
+ pkh: address,
828
+ value,
829
+ time_lock: 0 ,
830
+ } ] ;
831
+ let utxo_strategy = UtxoSelectionStrategy :: Random { from : None } ;
832
+ let script_inputs = vec ! [ Input {
833
+ output_pointer,
834
+ redeem_script: redeem_script_bytes,
835
+ } ] ;
836
+ let params = BuildScriptTransaction {
837
+ vto : vt_outputs,
838
+ fee,
839
+ utxo_strategy,
840
+ script_inputs,
841
+ change_address,
842
+ } ;
843
+ let request = format ! (
844
+ r#"{{"jsonrpc": "2.0","method": "sendScript", "params": {}, "id": "1"}}"# ,
845
+ serde_json:: to_string( & params) ?
846
+ ) ;
847
+ if dry_run {
848
+ println ! ( "{}" , request) ;
849
+ } else {
850
+ let response = send_request ( & mut stream, & request) ?;
851
+ let script_tx = parse_response :: < Transaction > ( & response) ?;
852
+ println ! ( "Created transaction:\n {:?}" , script_tx) ;
853
+ let script_transaction_hex = hex:: encode ( script_tx. to_pb_bytes ( ) . unwrap ( ) ) ;
854
+ println ! ( "Transaction bytes: {}" , script_transaction_hex) ;
811
855
}
812
856
Ok ( ( ) )
813
857
}
@@ -832,7 +876,13 @@ pub fn broadcast_tx(addr: SocketAddr, hex: String, dry_run: bool) -> Result<(),
832
876
Ok ( ( ) )
833
877
}
834
878
835
- pub fn sign_tx ( addr : SocketAddr , hex : String , dry_run : bool ) -> Result < ( ) , failure:: Error > {
879
+ pub fn sign_tx (
880
+ addr : SocketAddr ,
881
+ hex : String ,
882
+ input_index : usize ,
883
+ signature_position_in_witness : usize ,
884
+ dry_run : bool ,
885
+ ) -> Result < ( ) , failure:: Error > {
836
886
let mut stream = start_client ( addr) ?;
837
887
838
888
let mut tx: Transaction = Transaction :: from_pb_bytes ( & hex:: decode ( hex) ?) ?;
@@ -854,21 +904,122 @@ pub fn sign_tx(addr: SocketAddr, hex: String, dry_run: bool) -> Result<(), failu
854
904
match tx {
855
905
Transaction :: ValueTransfer ( ref mut vtt) => {
856
906
let signature_bytes = signature. to_pb_bytes ( ) ?;
857
- let mut script = witnet_stack:: decode ( & vtt. witness [ 0 ] ) ?;
907
+ // TODO: this only works if the witness field represents a script
908
+ // It could also represent a signature in the case of normal value transfer
909
+ // transactions. It would be nice to also support signing normal transactions here
910
+ let mut script = witnet_stack:: decode ( & vtt. witness [ input_index] ) ?;
911
+
912
+ println ! (
913
+ "-----------------------\n Previous witness:\n -----------------------\n {}" ,
914
+ witnet_stack:: parser:: script_to_string( & script)
915
+ ) ;
858
916
859
- println ! ( "Previous script:\n {:?}" , script) ;
860
- script. push ( Item :: Value ( MyValue :: Signature ( signature_bytes) ) ) ;
917
+ script. insert (
918
+ signature_position_in_witness,
919
+ Item :: Value ( MyValue :: Bytes ( signature_bytes) ) ,
920
+ ) ;
861
921
862
- println ! ( "Post script:\n {:?}" , script) ;
863
- let encoded_script = witnet_stack:: encode ( script) ?;
922
+ println ! (
923
+ "-----------------------\n New witness:\n -----------------------\n {}" ,
924
+ witnet_stack:: parser:: script_to_string( & script)
925
+ ) ;
926
+ let encoded_script = witnet_stack:: encode ( & script) ?;
864
927
865
- vtt. witness [ 0 ] = encoded_script;
928
+ vtt. witness [ input_index ] = encoded_script;
866
929
867
930
let script_transaction_hex = hex:: encode ( tx. to_pb_bytes ( ) . unwrap ( ) ) ;
868
931
println ! ( "Signed Transaction:\n {:?}" , tx) ;
869
- println ! ( "Script bytes: {}" , script_transaction_hex) ;
932
+ println ! ( "Signed Transaction hex bytes: {}" , script_transaction_hex) ;
870
933
}
871
- _ => unimplemented ! ( "We only can sign ScriptTransactions" ) ,
934
+ _ => unimplemented ! ( "We only can sign ValueTransfer transactions" ) ,
935
+ }
936
+ }
937
+
938
+ Ok ( ( ) )
939
+ }
940
+
941
+ pub fn add_tx_witness (
942
+ _addr : SocketAddr ,
943
+ hex : String ,
944
+ witness : String ,
945
+ input_index : usize ,
946
+ ) -> Result < ( ) , failure:: Error > {
947
+ let mut tx: Transaction = Transaction :: from_pb_bytes ( & hex:: decode ( hex) ?) ?;
948
+
949
+ println ! ( "Transaction to sign is:\n {:?}" , tx) ;
950
+
951
+ match tx {
952
+ Transaction :: ValueTransfer ( ref mut vtt) => {
953
+ let encoded_script = hex:: decode ( witness) ?;
954
+ vtt. witness [ input_index] = encoded_script;
955
+
956
+ let script_transaction_hex = hex:: encode ( tx. to_pb_bytes ( ) . unwrap ( ) ) ;
957
+ println ! ( "Signed Transaction:\n {:?}" , tx) ;
958
+ println ! ( "Signed Transaction hex bytes: {}" , script_transaction_hex) ;
959
+ }
960
+ _ => unimplemented ! ( "We only can sign ValueTransfer transactions" ) ,
961
+ }
962
+
963
+ Ok ( ( ) )
964
+ }
965
+
966
+ pub fn script_address ( hex : String ) -> Result < ( ) , failure:: Error > {
967
+ let script_bytes = hex:: decode ( hex) ?;
968
+ let script_pkh = PublicKeyHash :: from_script_bytes ( & script_bytes) ;
969
+ println ! (
970
+ "Script address (mainnet): {}" ,
971
+ script_pkh. bech32( Environment :: Mainnet )
972
+ ) ;
973
+ println ! (
974
+ "Script address (testnet): {}" ,
975
+ script_pkh. bech32( Environment :: Testnet )
976
+ ) ;
977
+
978
+ Ok ( ( ) )
979
+ }
980
+
981
+ pub fn address_to_bytes ( address : PublicKeyHash ) -> Result < ( ) , failure:: Error > {
982
+ let hex_address = hex:: encode ( address. as_ref ( ) ) ;
983
+ println ! ( "{}" , hex_address) ;
984
+
985
+ Ok ( ( ) )
986
+ }
987
+
988
+ /// Convert script text file into hex bytes
989
+ pub fn encode_script ( script_file : & Path ) -> Result < ( ) , failure:: Error > {
990
+ let script_str = std:: fs:: read_to_string ( script_file) ?;
991
+ let script = witnet_stack:: parser:: parse_script ( & script_str)
992
+ . map_err ( |e| format_err ! ( "Failed to parse script: {:?}" , e) ) ?;
993
+ let script_bytes = witnet_stack:: encode ( & script) ?;
994
+ let script_hex = hex:: encode ( & script_bytes) ;
995
+ let script_pkh = PublicKeyHash :: from_script_bytes ( & script_bytes) ;
996
+ println ! ( "Script address: {}" , script_pkh) ;
997
+
998
+ println ! ( "{}" , script_hex) ;
999
+
1000
+ Ok ( ( ) )
1001
+ }
1002
+
1003
+ /// Convert hex bytes into script text, and optionally write to file
1004
+ pub fn decode_script ( hex : String , script_file : Option < & Path > ) -> Result < ( ) , failure:: Error > {
1005
+ let script_bytes = hex:: decode ( hex) ?;
1006
+ let script_pkh = PublicKeyHash :: from_script_bytes ( & script_bytes) ;
1007
+ println ! ( "Script address: {}" , script_pkh) ;
1008
+
1009
+ let script = witnet_stack:: decode ( & script_bytes) ?;
1010
+
1011
+ let script_str = witnet_stack:: parser:: script_to_string ( & script) ;
1012
+
1013
+ match script_file {
1014
+ Some ( script_file) => {
1015
+ std:: fs:: write ( script_file, script_str) ?;
1016
+ println ! (
1017
+ "Script written to {}" ,
1018
+ script_file. canonicalize( ) ?. as_path( ) . display( )
1019
+ ) ;
1020
+ }
1021
+ None => {
1022
+ println ! ( "{}" , script_str) ;
872
1023
}
873
1024
}
874
1025
0 commit comments