@@ -15,6 +15,90 @@ function TransactionBuilder() {
15
15
this . tx = new Transaction ( )
16
16
}
17
17
18
+ // Static constructors
19
+ TransactionBuilder . fromTransaction = function ( transaction ) {
20
+ var txb = new TransactionBuilder ( )
21
+
22
+ // Extract/add inputs
23
+ transaction . ins . forEach ( function ( txin ) {
24
+ txb . addInput ( txin . hash , txin . index , txin . sequence )
25
+ } )
26
+
27
+ // Extract/add outputs
28
+ transaction . outs . forEach ( function ( txout ) {
29
+ txb . addOutput ( txout . script , txout . value )
30
+ } )
31
+
32
+ // Extract/add signatures
33
+ transaction . ins . forEach ( function ( txin ) {
34
+ // Ignore empty scripts
35
+ if ( txin . script . buffer . length === 0 ) return
36
+
37
+ var redeemScript
38
+ var scriptSig = txin . script
39
+ var scriptType = scripts . classifyInput ( scriptSig )
40
+
41
+ // Re-classify if P2SH
42
+ if ( scriptType === 'scripthash' ) {
43
+ redeemScript = Script . fromBuffer ( scriptSig . chunks . slice ( - 1 ) [ 0 ] )
44
+ scriptSig = Script . fromChunks ( scriptSig . chunks . slice ( 0 , - 1 ) )
45
+
46
+ scriptType = scripts . classifyInput ( scriptSig )
47
+ assert . equal ( scripts . classifyOutput ( redeemScript ) , scriptType , 'Non-matching scriptSig and scriptPubKey in input' )
48
+ }
49
+
50
+ // Extract hashType, pubKeys and signatures
51
+ var hashType , pubKeys , signatures
52
+
53
+ switch ( scriptType ) {
54
+ case 'pubkeyhash' :
55
+ var parsed = ECSignature . parseScriptSignature ( scriptSig . chunks [ 0 ] )
56
+ var pubKey = ECPubKey . fromBuffer ( scriptSig . chunks [ 1 ] )
57
+
58
+ hashType = parsed . hashType
59
+ pubKeys = [ pubKey ]
60
+ signatures = [ parsed . signature ]
61
+
62
+ break
63
+
64
+ case 'multisig' :
65
+ var scriptSigs = scriptSig . chunks . slice ( 1 ) // ignore OP_0
66
+ var parsed = scriptSigs . map ( function ( scriptSig ) {
67
+ return ECSignature . parseScriptSignature ( scriptSig )
68
+ } )
69
+
70
+ hashType = parsed [ 0 ] . hashType
71
+ pubKeys = [ ]
72
+ signatures = parsed . map ( function ( p ) { return p . signature } )
73
+
74
+ break
75
+
76
+ case 'pubkey' :
77
+ var parsed = ECSignature . parseScriptSignature ( scriptSig . chunks [ 0 ] )
78
+
79
+ hashType = parsed . hashType
80
+ pubKeys = [ ]
81
+ signatures = [ parsed . signature ]
82
+
83
+ break
84
+
85
+ default :
86
+ assert ( false , scriptType + ' not supported' )
87
+ }
88
+
89
+ txb . signatures [ txin . index ] = {
90
+ hashType : hashType ,
91
+ pubKeys : pubKeys ,
92
+ redeemScript : redeemScript ,
93
+ scriptType : scriptType ,
94
+ signatures : signatures
95
+ }
96
+ } )
97
+
98
+ return txb
99
+ }
100
+
101
+ // Operations
18
102
TransactionBuilder . prototype . addInput = function ( prevTx , index , sequence , prevOutScript ) {
19
103
var prevOutHash
20
104
@@ -63,55 +147,6 @@ TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
63
147
return this . tx . addOutput ( scriptPubKey , value )
64
148
}
65
149
66
- TransactionBuilder . prototype . sign = function ( index , privKey , redeemScript , hashType ) {
67
- assert ( this . tx . ins . length >= index , 'No input at index: ' + index )
68
- hashType = hashType || Transaction . SIGHASH_ALL
69
-
70
- var prevOutScript = this . prevOutScripts [ index ]
71
- var prevOutType = this . prevOutTypes [ index ]
72
-
73
- var scriptType , hash
74
- if ( redeemScript ) {
75
- prevOutScript = prevOutScript || scripts . scriptHashOutput ( redeemScript . getHash ( ) )
76
- prevOutType = prevOutType || 'scripthash'
77
-
78
- assert . equal ( prevOutType , 'scripthash' , 'PrevOutScript must be P2SH' )
79
-
80
- scriptType = scripts . classifyOutput ( redeemScript )
81
-
82
- assert . notEqual ( scriptType , 'scripthash' , 'RedeemScript can\'t be P2SH' )
83
- assert . notEqual ( scriptType , 'nonstandard' , 'RedeemScript not supported (nonstandard)' )
84
-
85
- hash = this . tx . hashForSignature ( index , redeemScript , hashType )
86
-
87
- } else {
88
- prevOutScript = prevOutScript || privKey . pub . getAddress ( ) . toOutputScript ( )
89
- scriptType = prevOutType || 'pubkeyhash'
90
-
91
- assert . notEqual ( scriptType , 'scripthash' , 'PrevOutScript requires redeemScript' )
92
-
93
- hash = this . tx . hashForSignature ( index , prevOutScript , hashType )
94
- }
95
-
96
- if ( ! ( index in this . signatures ) ) {
97
- this . signatures [ index ] = {
98
- hashType : hashType ,
99
- pubKeys : [ ] ,
100
- redeemScript : redeemScript ,
101
- scriptType : scriptType ,
102
- signatures : [ ]
103
- }
104
- }
105
-
106
- var input = this . signatures [ index ]
107
- assert . equal ( input . hashType , hashType , 'Inconsistent hashType' )
108
- assert . deepEqual ( input . redeemScript , redeemScript , 'Inconsistent redeemScript' )
109
-
110
- var signature = privKey . sign ( hash )
111
- input . pubKeys . push ( privKey . pub )
112
- input . signatures . push ( signature )
113
- }
114
-
115
150
TransactionBuilder . prototype . build = function ( ) {
116
151
return this . __build ( false )
117
152
}
@@ -173,86 +208,53 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
173
208
return tx
174
209
}
175
210
176
- TransactionBuilder . fromTransaction = function ( transaction ) {
177
- var txb = new TransactionBuilder ( )
178
-
179
- // Extract/add inputs
180
- transaction . ins . forEach ( function ( txin ) {
181
- txb . addInput ( txin . hash , txin . index , txin . sequence )
182
- } )
183
-
184
- // Extract/add outputs
185
- transaction . outs . forEach ( function ( txout ) {
186
- txb . addOutput ( txout . script , txout . value )
187
- } )
188
-
189
- // Extract/add signatures
190
- transaction . ins . forEach ( function ( txin ) {
191
- // Ignore empty scripts
192
- if ( txin . script . buffer . length === 0 ) return
193
-
194
- var redeemScript
195
- var scriptSig = txin . script
196
- var scriptType = scripts . classifyInput ( scriptSig )
197
-
198
- // Re-classify if P2SH
199
- if ( scriptType === 'scripthash' ) {
200
- redeemScript = Script . fromBuffer ( scriptSig . chunks . slice ( - 1 ) [ 0 ] )
201
- scriptSig = Script . fromChunks ( scriptSig . chunks . slice ( 0 , - 1 ) )
202
-
203
- scriptType = scripts . classifyInput ( scriptSig )
204
- assert . equal ( scripts . classifyOutput ( redeemScript ) , scriptType , 'Non-matching scriptSig and scriptPubKey in input' )
205
- }
206
-
207
- // Extract hashType, pubKeys and signatures
208
- var hashType , pubKeys , signatures
209
-
210
- switch ( scriptType ) {
211
- case 'pubkeyhash' :
212
- var parsed = ECSignature . parseScriptSignature ( scriptSig . chunks [ 0 ] )
213
- var pubKey = ECPubKey . fromBuffer ( scriptSig . chunks [ 1 ] )
211
+ TransactionBuilder . prototype . sign = function ( index , privKey , redeemScript , hashType ) {
212
+ assert ( this . tx . ins . length >= index , 'No input at index: ' + index )
213
+ hashType = hashType || Transaction . SIGHASH_ALL
214
214
215
- hashType = parsed . hashType
216
- pubKeys = [ pubKey ]
217
- signatures = [ parsed . signature ]
215
+ var prevOutScript = this . prevOutScripts [ index ]
216
+ var prevOutType = this . prevOutTypes [ index ]
218
217
219
- break
218
+ var scriptType , hash
219
+ if ( redeemScript ) {
220
+ prevOutScript = prevOutScript || scripts . scriptHashOutput ( redeemScript . getHash ( ) )
221
+ prevOutType = prevOutType || 'scripthash'
220
222
221
- case 'multisig' :
222
- var scriptSigs = scriptSig . chunks . slice ( 1 ) // ignore OP_0
223
- var parsed = scriptSigs . map ( function ( scriptSig ) {
224
- return ECSignature . parseScriptSignature ( scriptSig )
225
- } )
223
+ assert . equal ( prevOutType , 'scripthash' , 'PrevOutScript must be P2SH' )
226
224
227
- hashType = parsed [ 0 ] . hashType
228
- pubKeys = [ ]
229
- signatures = parsed . map ( function ( p ) { return p . signature } )
225
+ scriptType = scripts . classifyOutput ( redeemScript )
230
226
231
- break
227
+ assert . notEqual ( scriptType , 'scripthash' , 'RedeemScript can\'t be P2SH' )
228
+ assert . notEqual ( scriptType , 'nonstandard' , 'RedeemScript not supported (nonstandard)' )
232
229
233
- case 'pubkey' :
234
- var parsed = ECSignature . parseScriptSignature ( scriptSig . chunks [ 0 ] )
230
+ hash = this . tx . hashForSignature ( index , redeemScript , hashType )
235
231
236
- hashType = parsed . hashType
237
- pubKeys = [ ]
238
- signatures = [ parsed . signature ]
232
+ } else {
233
+ prevOutScript = prevOutScript || privKey . pub . getAddress ( ) . toOutputScript ( )
234
+ scriptType = prevOutType || 'pubkeyhash'
239
235
240
- break
236
+ assert . notEqual ( scriptType , 'scripthash' , 'PrevOutScript requires redeemScript' )
241
237
242
- default :
243
- assert ( false , scriptType + ' not supported' )
244
- }
238
+ hash = this . tx . hashForSignature ( index , prevOutScript , hashType )
239
+ }
245
240
246
- txb . signatures [ txin . index ] = {
241
+ if ( ! ( index in this . signatures ) ) {
242
+ this . signatures [ index ] = {
247
243
hashType : hashType ,
248
- pubKeys : pubKeys ,
244
+ pubKeys : [ ] ,
249
245
redeemScript : redeemScript ,
250
246
scriptType : scriptType ,
251
- signatures : signatures
247
+ signatures : [ ]
252
248
}
253
- } )
249
+ }
254
250
255
- return txb
251
+ var input = this . signatures [ index ]
252
+ assert . equal ( input . hashType , hashType , 'Inconsistent hashType' )
253
+ assert . deepEqual ( input . redeemScript , redeemScript , 'Inconsistent redeemScript' )
254
+
255
+ var signature = privKey . sign ( hash )
256
+ input . pubKeys . push ( privKey . pub )
257
+ input . signatures . push ( signature )
256
258
}
257
259
258
260
module . exports = TransactionBuilder
0 commit comments