1
1
var assert = require ( 'assert' )
2
2
var scripts = require ( './scripts' )
3
3
4
- var ECKey = require ( './eckey ' )
5
- var Transaction = require ( './transaction ' )
4
+ var ECPubKey = require ( './ecpubkey ' )
5
+ var ECSignature = require ( './ecsignature ' )
6
6
var Script = require ( './script' )
7
+ var Transaction = require ( './transaction' )
7
8
8
9
function TransactionBuilder ( ) {
9
10
this . prevOutMap = { }
@@ -14,7 +15,7 @@ function TransactionBuilder() {
14
15
this . tx = new Transaction ( )
15
16
}
16
17
17
- TransactionBuilder . prototype . addInput = function ( prevTx , index , prevOutScript , sequence ) {
18
+ TransactionBuilder . prototype . addInput = function ( prevTx , index , sequence , prevOutScript ) {
18
19
var prevOutHash
19
20
20
21
if ( typeof prevTx === 'string' ) {
@@ -103,7 +104,6 @@ TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashT
103
104
}
104
105
105
106
var input = this . signatures [ index ]
106
-
107
107
assert . equal ( input . hashType , hashType , 'Inconsistent hashType' )
108
108
assert . deepEqual ( input . redeemScript , redeemScript , 'Inconsistent redeemScript' )
109
109
@@ -130,29 +130,34 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
130
130
131
131
var tx = this . tx . clone ( )
132
132
133
+ // Create script signatures from signature meta-data
133
134
this . signatures . forEach ( function ( input , index ) {
134
135
var scriptSig
136
+ var scriptType = input . scriptType
135
137
136
138
var signatures = input . signatures . map ( function ( signature ) {
137
139
return signature . toScriptSignature ( input . hashType )
138
140
} )
139
141
140
- if ( input . scriptType === 'pubkeyhash' ) {
141
- var signature = signatures [ 0 ]
142
- var publicKey = input . pubKeys [ 0 ]
143
- scriptSig = scripts . pubKeyHashInput ( signature , publicKey )
144
-
145
- } else if ( input . scriptType === 'multisig' ) {
146
- var redeemScript = allowIncomplete ? undefined : input . redeemScript
147
- scriptSig = scripts . multisigInput ( signatures , redeemScript )
148
-
149
- } else if ( input . scriptType === 'pubkey' ) {
150
- var signature = signatures [ 0 ]
151
- scriptSig = scripts . pubKeyInput ( signature )
152
-
153
- } else {
154
- assert ( false , input . scriptType + ' not supported' )
155
-
142
+ switch ( scriptType ) {
143
+ case 'pubkeyhash' :
144
+ var signature = signatures [ 0 ]
145
+ var pubKey = input . pubKeys [ 0 ]
146
+ scriptSig = scripts . pubKeyHashInput ( signature , pubKey )
147
+
148
+ break
149
+ case 'multisig' :
150
+ var redeemScript = allowIncomplete ? undefined : input . redeemScript
151
+ scriptSig = scripts . multisigInput ( signatures , redeemScript )
152
+
153
+ break
154
+ case 'pubkey' :
155
+ var signature = signatures [ 0 ]
156
+ scriptSig = scripts . pubKeyInput ( signature )
157
+
158
+ break
159
+ default :
160
+ assert ( false , scriptType + ' not supported' )
156
161
}
157
162
158
163
if ( input . redeemScript ) {
@@ -165,4 +170,83 @@ TransactionBuilder.prototype.__build = function(allowIncomplete) {
165
170
return tx
166
171
}
167
172
173
+ TransactionBuilder . fromTransaction = function ( transaction ) {
174
+ var txb = new TransactionBuilder ( )
175
+
176
+ // Extract/add inputs
177
+ transaction . ins . forEach ( function ( txin ) {
178
+ txb . addInput ( txin . hash , txin . index , txin . sequence )
179
+ } )
180
+
181
+ // Extract/add outputs
182
+ transaction . outs . forEach ( function ( txout ) {
183
+ txb . addOutput ( txout . script , txout . value )
184
+ } )
185
+
186
+ // Extract/add signatures
187
+ transaction . ins . forEach ( function ( txin ) {
188
+ // Ignore empty scripts
189
+ if ( txin . script . buffer . length === 0 ) return
190
+
191
+ var redeemScript
192
+ var scriptSig = txin . script
193
+ var scriptType = scripts . classifyInput ( scriptSig )
194
+
195
+ // Re-classify if P2SH
196
+ if ( scriptType === 'scripthash' ) {
197
+ redeemScript = Script . fromBuffer ( scriptSig . chunks . slice ( - 1 ) [ 0 ] )
198
+ scriptSig = Script . fromChunks ( scriptSig . chunks . slice ( 0 , - 1 ) )
199
+
200
+ scriptType = scripts . classifyInput ( scriptSig )
201
+ assert . equal ( scripts . classifyOutput ( redeemScript ) , scriptType , 'Non-matching scriptSig and scriptPubKey in input' )
202
+ }
203
+
204
+ // Extract hashType, pubKeys and signatures
205
+ var hashType , pubKeys , signatures
206
+
207
+ switch ( scriptType ) {
208
+ case 'pubkeyhash' :
209
+ var parsed = ECSignature . parseScriptSignature ( scriptSig . chunks [ 0 ] )
210
+ var pubKey = ECPubKey . fromBuffer ( scriptSig . chunks [ 1 ] )
211
+
212
+ hashType = parsed . hashType
213
+ pubKeys = [ pubKey ]
214
+ signatures = [ parsed . signature ]
215
+
216
+ break
217
+ case 'multisig' :
218
+ var scriptSigs = scriptSig . chunks . slice ( 1 ) // ignore OP_0
219
+ var parsed = scriptSigs . map ( function ( scriptSig ) {
220
+ return ECSignature . parseScriptSignature ( scriptSig )
221
+ } )
222
+
223
+ hashType = parsed [ 0 ] . hashType
224
+ pubKeys = [ ]
225
+ signatures = parsed . map ( function ( p ) { return p . signature } )
226
+
227
+ break
228
+ case 'pubkey' :
229
+ var parsed = ECSignature . parseScriptSignature ( scriptSig . chunks [ 0 ] )
230
+
231
+ hashType = parsed . hashType
232
+ pubKeys = [ ]
233
+ signatures = [ parsed . signature ]
234
+
235
+ break
236
+ default :
237
+ assert ( false , scriptType + ' not supported' )
238
+ }
239
+
240
+ txb . signatures [ txin . index ] = {
241
+ hashType : hashType ,
242
+ pubKeys : pubKeys ,
243
+ redeemScript : redeemScript ,
244
+ scriptType : scriptType ,
245
+ signatures : signatures
246
+ }
247
+ } )
248
+
249
+ return txb
250
+ }
251
+
168
252
module . exports = TransactionBuilder
0 commit comments