11use ansi_term:: Color :: { Purple , Red , White , Yellow } ;
2- use failure:: { bail, Fail } ;
2+ use failure:: { bail, format_err , Fail } ;
33use itertools:: Itertools ;
44use num_format:: { Locale , ToFormattedString } ;
55use prettytable:: { cell, row, Table } ;
@@ -711,7 +711,6 @@ pub fn master_key_export(
711711 Ok ( ( ) )
712712}
713713
714- #[ allow( clippy:: too_many_arguments) ]
715714pub fn create_multisig_address (
716715 n : u8 ,
717716 m : u8 ,
@@ -736,12 +735,11 @@ pub fn create_multisig_address(
736735 Item :: Operator ( MyOperator :: CheckMultiSig ) ,
737736 ] ) ;
738737
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) ?) ;
741739
742740 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
745743 ) ;
746744
747745 Ok ( ( ) )
@@ -778,7 +776,7 @@ pub fn create_opened_multisig(
778776 Item :: Value ( MyValue :: Integer ( i128 :: from( n) ) ) ,
779777 Item :: Operator ( MyOperator :: CheckMultiSig ) ,
780778 ] ) ;
781- let redeem_script_bytes = witnet_stack:: encode ( redeem_script) ?;
779+ let redeem_script_bytes = witnet_stack:: encode ( & redeem_script) ?;
782780 let vt_outputs = vec ! [ ValueTransferOutput {
783781 pkh: address,
784782 value,
@@ -807,7 +805,53 @@ pub fn create_opened_multisig(
807805 let script_tx = parse_response :: < Transaction > ( & response) ?;
808806 println ! ( "Created transaction:\n {:?}" , script_tx) ;
809807 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) ;
811855 }
812856 Ok ( ( ) )
813857}
@@ -832,7 +876,13 @@ pub fn broadcast_tx(addr: SocketAddr, hex: String, dry_run: bool) -> Result<(),
832876 Ok ( ( ) )
833877}
834878
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 > {
836886 let mut stream = start_client ( addr) ?;
837887
838888 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
854904 match tx {
855905 Transaction :: ValueTransfer ( ref mut vtt) => {
856906 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+ ) ;
858916
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+ ) ;
861921
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) ?;
864927
865- vtt. witness [ 0 ] = encoded_script;
928+ vtt. witness [ input_index ] = encoded_script;
866929
867930 let script_transaction_hex = hex:: encode ( tx. to_pb_bytes ( ) . unwrap ( ) ) ;
868931 println ! ( "Signed Transaction:\n {:?}" , tx) ;
869- println ! ( "Script bytes: {}" , script_transaction_hex) ;
932+ println ! ( "Signed Transaction hex bytes: {}" , script_transaction_hex) ;
870933 }
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) ;
8721023 }
8731024 }
8741025
0 commit comments