34
34
* @prop {Function } _createMemoScript
35
35
* @prop {Function } _hash
36
36
* @prop {Function } _hashAndSignAll
37
+ * @prop {Function } _hashAndSignOne
37
38
* @prop {Function } _legacyMustSelectInputs
38
39
* @prop {Function } _legacySelectOptimalUtxos
39
40
* @prop {Function } _packInputs
59
60
/**
60
61
* @typedef tx
61
62
* @prop {TxHashAndSignAll } hashAndSignAll
63
+ * @prop {TxHashAndSignOne } hashAndSignOne
62
64
*/
63
65
64
66
/** @type {Tx } */
@@ -242,7 +244,60 @@ var DashTx = ("object" === typeof module && exports) || {};
242
244
}
243
245
void Tx . _addPrivKeyUtils ( privUtils , keys ) ;
244
246
245
- return await Tx . _hashAndSignAll ( txInfo , privUtils ) ;
247
+ let sortedInputs = txInfo . inputs . slice ( 0 ) ;
248
+ sortedInputs . sort ( Tx . sortInputs ) ;
249
+ for ( let i = 0 ; i < sortedInputs . length ; i += 1 ) {
250
+ let isSelf = sortedInputs [ i ] === txInfo . inputs [ i ] ;
251
+ if ( ! isSelf ) {
252
+ console . warn (
253
+ `txInfo.inputs are not ordered correctly, use txInfo.inputs.sort(Tx.sortInputs)\n(this will be an exception in the next version)` ,
254
+ ) ;
255
+ break ;
256
+ }
257
+ }
258
+
259
+ let sortedOutputs = txInfo . outputs . slice ( 0 ) ;
260
+ sortedOutputs . sort ( Tx . sortOutputs ) ;
261
+ for ( let i = 0 ; i < sortedOutputs . length ; i += 1 ) {
262
+ let isSelf = sortedOutputs [ i ] === txInfo . outputs [ i ] ;
263
+ if ( ! isSelf ) {
264
+ console . warn (
265
+ `txInfo.outputs are not ordered correctly, use txInfo.outputs.sort(Tx.sortOutputs)\n(this will be an exception in the next version)` ,
266
+ ) ;
267
+ break ;
268
+ }
269
+ }
270
+
271
+ /** @type {TxInfoSigned } */
272
+ let txInfoSigned = {
273
+ /** @type {Array<TxInputSigned> } */
274
+ inputs : [ ] ,
275
+ outputs : txInfo . outputs ,
276
+ version : txInfo . version || CURRENT_VERSION ,
277
+ locktime : txInfo . locktime || 0x00 ,
278
+ transaction : "" ,
279
+ } ;
280
+
281
+ return await Tx . _hashAndSignAll ( txInfoSigned , txInfo , privUtils ) ;
282
+ } ;
283
+
284
+ /** @type {TxHashAndSignAll } */
285
+ txInst . hashAndSignOne = async function ( txInfo , i ) {
286
+ let privUtils = Object . assign ( { } , keyUtils ) ;
287
+ void Tx . _addPrivKeyUtils ( keyUtils , null ) ;
288
+
289
+ /** @type {TxInfoSigned } */
290
+ let txInfoSigned = {
291
+ /** @type {Array<TxInputSigned> } */
292
+ inputs : [ ] ,
293
+ outputs : txInfo . outputs ,
294
+ version : txInfo . version || CURRENT_VERSION ,
295
+ locktime : txInfo . locktime || 0x00 ,
296
+ transaction : "" ,
297
+ } ;
298
+
299
+ let txInputSigned = await Tx . _hashAndSignOne ( privUtils , txInfo , i ) ;
300
+ txInfoSigned . inputs [ i ] = txInputSigned ;
246
301
} ;
247
302
248
303
txInst . legacy = { } ;
@@ -889,6 +944,7 @@ var DashTx = ("object" === typeof module && exports) || {};
889
944
} ;
890
945
891
946
/**
947
+ * @param {TxInfoSigned } txInfoSigned
892
948
* @param {TxInfo } txInfo
893
949
* TODO _param {Array<TxInputRaw>} txInfo.inputs - needs type narrowing check
894
950
* TODO _param {Array<TxOutput>} txInfo.outputs
@@ -897,128 +953,105 @@ var DashTx = ("object" === typeof module && exports) || {};
897
953
* @param {TxDeps } keyUtils
898
954
* @returns {Promise<TxInfoSigned> }
899
955
*/
900
- Tx . _hashAndSignAll = async function ( txInfo , keyUtils ) {
901
- let sortedInputs = txInfo . inputs . slice ( 0 ) ;
902
- sortedInputs . sort ( Tx . sortInputs ) ;
903
- for ( let i = 0 ; i < sortedInputs . length ; i += 1 ) {
904
- let isSelf = sortedInputs [ i ] === txInfo . inputs [ i ] ;
905
- if ( ! isSelf ) {
906
- console . warn (
907
- `txInfo.inputs are not ordered correctly, use txInfo.inputs.sort(Tx.sortInputs)\n(this will be an exception in the next version)` ,
908
- ) ;
909
- break ;
910
- }
956
+ Tx . _hashAndSignAll = async function ( txInfoSigned , txInfo , keyUtils ) {
957
+ for ( let i = 0 ; i < txInfo . inputs . length ; i += 1 ) {
958
+ let txInputSigned = await DashTx . _hashAndSignOne ( keyUtils , txInfo , i ) ;
959
+ txInfoSigned . inputs [ i ] = txInputSigned ;
911
960
}
912
961
913
- let sortedOutputs = txInfo . outputs . slice ( 0 ) ;
914
- sortedOutputs . sort ( Tx . sortOutputs ) ;
915
- for ( let i = 0 ; i < sortedOutputs . length ; i += 1 ) {
916
- let isSelf = sortedOutputs [ i ] === txInfo . outputs [ i ] ;
917
- if ( ! isSelf ) {
918
- console . warn (
919
- `txInfo.outputs are not ordered correctly, use txInfo.outputs.sort(Tx.sortOutputs)\n(this will be an exception in the next version)` ,
920
- ) ;
921
- break ;
922
- }
923
- }
962
+ let transaction = Tx . createSigned ( txInfoSigned ) ;
924
963
925
- /** @type { TxInfoSigned } */
926
- let txInfoSigned = {
927
- /** @type { Array<TxInputSigned> } */
928
- inputs : [ ] ,
964
+ return {
965
+ // @ts -ignore - tsc doesn't support an enum here
966
+ inputs : txInfo . inputs ,
967
+ locktime : txInfo . locktime || 0x0 ,
929
968
outputs : txInfo . outputs ,
969
+ transaction : transaction ,
930
970
version : txInfo . version || CURRENT_VERSION ,
931
- locktime : txInfo . locktime || 0x00 ,
932
- transaction : "" ,
933
971
} ;
972
+ } ;
934
973
935
- /**
936
- * @param {TxPrivateKey } privKey
937
- */
938
- function createGetPrivateKey ( privKey ) {
939
- return function ( ) {
940
- return privKey ;
941
- } ;
942
- }
943
-
944
- function throwGetPrivateKeyError ( ) {
945
- if ( false ) {
946
- return new Uint8Array ( 0 ) ;
947
- }
974
+ /**
975
+ * @param {TxPrivateKey } privKey
976
+ */
977
+ function createGetPrivateKey ( privKey ) {
978
+ return function ( ) {
979
+ return privKey ;
980
+ } ;
981
+ }
948
982
949
- const msg =
950
- "getPrivateKey() is only valid for the lifetime of transaction signing process" ;
951
- throw new Error ( msg ) ;
983
+ function throwGetPrivateKeyError ( ) {
984
+ if ( false ) {
985
+ return new Uint8Array ( 0 ) ;
952
986
}
953
987
954
- for ( let i = 0 ; i < txInfo . inputs . length ; i += 1 ) {
955
- let txInput = txInfo . inputs [ i ] ;
956
- // TODO script -> lockScript, sigScript
957
- //let lockScriptHex = txInput.script;
958
- let _sigHashType = txInput . sigHashType ?? Tx . SIGHASH_ALL ;
959
- let txHashable = Tx . createHashable ( txInfo , i ) ;
960
- let txHashBuf = await Tx . hashPartial ( txHashable , _sigHashType ) ;
961
- let privKey = await keyUtils . getPrivateKey ( txInput , i , txInfo . inputs ) ;
962
-
963
- let sigBuf = await keyUtils . sign ( privKey , txHashBuf ) ;
964
- let sigHex = "" ;
965
- if ( "string" === typeof sigBuf ) {
966
- console . warn ( `sign() should return a Uint8Array of an ASN.1 signature` ) ;
967
- sigHex = sigBuf ;
968
- } else {
969
- sigHex = Tx . utils . bytesToHex ( sigBuf ) ;
970
- }
971
-
972
- let pubKeyHex = txInput . publicKey ;
973
- if ( ! pubKeyHex ) {
974
- let getPrivateKey = createGetPrivateKey ( privKey ) ;
975
- let _txInput = Object . assign ( { } , { getPrivateKey } , txInput ) ;
976
- let pubKey = await keyUtils . getPublicKey ( _txInput , i , txInfo . inputs ) ;
977
- pubKeyHex = Tx . utils . bytesToHex ( pubKey ) ;
978
- _txInput . getPrivateKey = throwGetPrivateKeyError ;
979
- }
980
- if ( "string" !== typeof pubKeyHex ) {
981
- let warn = new Error ( "stack" ) ;
982
- console . warn (
983
- `utxo inputs should be plain JSON and use hex rather than buffers for 'publicKey'` ,
984
- warn . stack ,
985
- ) ;
986
- pubKeyHex = Tx . utils . bytesToHex ( pubKeyHex ) ;
987
- }
988
-
989
- /** @type TxInputSigned */
990
- let txInputSigned = {
991
- txId : txInput . txId || txInput . txid ,
992
- txid : txInput . txId || txInput . txid ,
993
- outputIndex : txInput . outputIndex ,
994
- signature : sigHex ,
995
- publicKey : pubKeyHex ,
996
- sigHashType : _sigHashType ,
997
- } ;
998
-
999
- // expose _actual_ values used, for debugging
1000
- let txHashHex = Tx . utils . bytesToHex ( txHashBuf ) ;
1001
- Object . assign ( {
1002
- _hash : txHashHex ,
1003
- _signature : sigHex . toString ( ) ,
1004
- _lockScript : txInfo . inputs [ i ] . script ,
1005
- _publicKey : pubKeyHex ,
1006
- _sigHashType : _sigHashType ,
1007
- } ) ;
988
+ const msg =
989
+ "getPrivateKey() is only valid for the lifetime of transaction signing process" ;
990
+ throw new Error ( msg ) ;
991
+ }
1008
992
1009
- txInfoSigned . inputs [ i ] = txInputSigned ;
993
+ /**
994
+ * @param {TxInfo } txInfo
995
+ * @param {TxDeps } keyUtils
996
+ * @param {Number } i - which input to try to sign
997
+ * @returns {Promise<TxInputSigned> }
998
+ */
999
+ Tx . _hashAndSignOne = async function ( keyUtils , txInfo , i ) {
1000
+ let txInput = txInfo . inputs [ i ] ;
1001
+ // TODO script -> lockScript, sigScript
1002
+ //let lockScriptHex = txInput.script;
1003
+ let _sigHashType = txInput . sigHashType ?? Tx . SIGHASH_ALL ;
1004
+ let txHashable = Tx . createHashable ( txInfo , i ) ;
1005
+ let txHashBuf = await Tx . hashPartial ( txHashable , _sigHashType ) ;
1006
+ let privKey = await keyUtils . getPrivateKey ( txInput , i , txInfo . inputs ) ;
1007
+
1008
+ let sigBuf = await keyUtils . sign ( privKey , txHashBuf ) ;
1009
+ let sigHex = "" ;
1010
+ if ( "string" === typeof sigBuf ) {
1011
+ console . warn ( `sign() should return a Uint8Array of an ASN.1 signature` ) ;
1012
+ sigHex = sigBuf ;
1013
+ } else {
1014
+ sigHex = Tx . utils . bytesToHex ( sigBuf ) ;
1010
1015
}
1011
1016
1012
- let transaction = Tx . createSigned ( txInfoSigned ) ;
1017
+ let pubKeyHex = txInput . publicKey ;
1018
+ if ( ! pubKeyHex ) {
1019
+ let getPrivateKey = createGetPrivateKey ( privKey ) ;
1020
+ let _txInput = Object . assign ( { } , { getPrivateKey } , txInput ) ;
1021
+ let pubKey = await keyUtils . getPublicKey ( _txInput , i , txInfo . inputs ) ;
1022
+ pubKeyHex = Tx . utils . bytesToHex ( pubKey ) ;
1023
+ _txInput . getPrivateKey = throwGetPrivateKeyError ;
1024
+ }
1025
+ if ( "string" !== typeof pubKeyHex ) {
1026
+ let warn = new Error ( "stack" ) ;
1027
+ console . warn (
1028
+ `utxo inputs should be plain JSON and use hex rather than buffers for 'publicKey'` ,
1029
+ warn . stack ,
1030
+ ) ;
1031
+ pubKeyHex = Tx . utils . bytesToHex ( pubKeyHex ) ;
1032
+ }
1013
1033
1014
- return {
1015
- //@ts -ignore - tsc doesn't support an enum here
1016
- inputs : txInfo . inputs ,
1017
- locktime : txInfo . locktime || 0x0 ,
1018
- outputs : txInfo . outputs ,
1019
- transaction : transaction ,
1020
- version : txInfo . version || CURRENT_VERSION ,
1034
+ /** @type TxInputSigned */
1035
+ let txInputSigned = {
1036
+ txId : txInput . txId || txInput . txid ,
1037
+ txid : txInput . txId || txInput . txid ,
1038
+ outputIndex : txInput . outputIndex ,
1039
+ signature : sigHex ,
1040
+ publicKey : pubKeyHex ,
1041
+ sigHashType : _sigHashType ,
1021
1042
} ;
1043
+
1044
+ // expose _actual_ values used, for debugging
1045
+ let txHashHex = Tx . utils . bytesToHex ( txHashBuf ) ;
1046
+ Object . assign ( {
1047
+ _hash : txHashHex ,
1048
+ _signature : sigHex . toString ( ) ,
1049
+ _lockScript : txInfo . inputs [ i ] . script ,
1050
+ _publicKey : pubKeyHex ,
1051
+ _sigHashType : _sigHashType ,
1052
+ } ) ;
1053
+
1054
+ return txInputSigned ;
1022
1055
} ;
1023
1056
1024
1057
Tx . createRaw = function ( opts ) {
@@ -1851,6 +1884,12 @@ if ("object" === typeof module) {
1851
1884
* @param {Array<TxPrivateKey> } [keys]
1852
1885
*/
1853
1886
1887
+ /**
1888
+ * @callback TxHashAndSignOne
1889
+ * @param {TxInfo } txInfo
1890
+ * @param {Number } i - which to sign
1891
+ */
1892
+
1854
1893
/**
1855
1894
* @callback TxHashPartial
1856
1895
* @param {String } txHex - signable tx hex (like raw tx, but with (lock)script)
0 commit comments