@@ -177,6 +177,8 @@ Transaction.prototype.clone = function () {
177177 return newTx
178178}
179179
180+ var one = new Buffer ( '0000000000000000000000000000000000000000000000000000000000000001' , 'hex' )
181+
180182/**
181183 * Hash transaction for signing a specific input.
182184 *
@@ -191,33 +193,71 @@ Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashT
191193 typeForce ( 'Number' , hashType )
192194
193195 assert ( inIndex >= 0 , 'Invalid vin index' )
194- assert ( inIndex < this . ins . length , 'Invalid vin index' )
196+
197+ // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29
198+ if ( inIndex >= this . ins . length ) return one
195199
196200 var txTmp = this . clone ( )
201+
202+ // in case concatenating two scripts ends up with two codeseparators,
203+ // or an extra one at the end, this prevents all those possible incompatibilities.
197204 var hashScript = prevOutScript . without ( opcodes . OP_CODESEPARATOR )
205+ var i
198206
199- // Blank out other inputs' signatures
200- txTmp . ins . forEach ( function ( txIn ) {
201- txIn . script = Script . EMPTY
202- } )
207+ // blank out other inputs' signatures
208+ txTmp . ins . forEach ( function ( input ) { input . script = Script . EMPTY } )
203209 txTmp . ins [ inIndex ] . script = hashScript
204210
205- var hashTypeModifier = hashType & 0x1f
211+ // blank out some of the inputs
212+ if ( ( hashType & 0x1f ) === Transaction . SIGHASH_NONE ) {
213+ // wildcard payee
214+ txTmp . outs = [ ]
215+
216+ // let the others update at will
217+ txTmp . ins . forEach ( function ( input , i ) {
218+ if ( i !== inIndex ) {
219+ input . sequence = 0
220+ }
221+ } )
222+
223+ } else if ( ( hashType & 0x1f ) === Transaction . SIGHASH_SINGLE ) {
224+ var nOut = inIndex
225+
226+ // only lock-in the txout payee at same index as txIn
227+ // https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60
228+ if ( nOut >= this . outs . length ) return one
229+
230+ txTmp . outs = txTmp . outs . slice ( 0 , nOut + 1 )
206231
207- if ( hashTypeModifier === Transaction . SIGHASH_NONE ) {
208- assert ( false , 'SIGHASH_NONE not yet supported' )
209- } else if ( hashTypeModifier === Transaction . SIGHASH_SINGLE ) {
210- assert ( false , 'SIGHASH_SINGLE not yet supported' )
232+ // blank all other outputs (clear scriptPubKey, value === -1)
233+ var stubOut = {
234+ script : Script . EMPTY ,
235+ valueBuffer : new Buffer ( 'ffffffffffffffff' , 'hex' )
236+ }
237+
238+ for ( i = 0 ; i < nOut ; i ++ ) {
239+ txTmp . outs [ i ] = stubOut
240+ }
241+
242+ // let the others update at will
243+ txTmp . ins . forEach ( function ( input , i ) {
244+ if ( i !== inIndex ) {
245+ input . sequence = 0
246+ }
247+ } )
211248 }
212249
250+ // blank out other inputs completely, not recommended for open transactions
213251 if ( hashType & Transaction . SIGHASH_ANYONECANPAY ) {
214- assert ( false , 'SIGHASH_ANYONECANPAY not yet supported' )
252+ txTmp . ins [ 0 ] = txTmp . ins [ inIndex ]
253+ txTmp . ins = txTmp . ins . slice ( 0 , 1 )
215254 }
216255
217- var hashTypeBuffer = new Buffer ( 4 )
218- hashTypeBuffer . writeInt32LE ( hashType , 0 )
256+ // serialize and hash
257+ var buffer = new Buffer ( txTmp . byteLength ( ) + 4 )
258+ buffer . writeInt32LE ( hashType , buffer . length - 4 )
259+ txTmp . toBuffer ( ) . copy ( buffer , 0 )
219260
220- var buffer = Buffer . concat ( [ txTmp . toBuffer ( ) , hashTypeBuffer ] )
221261 return crypto . hash256 ( buffer )
222262}
223263
@@ -267,7 +307,12 @@ Transaction.prototype.toBuffer = function () {
267307
268308 writeVarInt ( this . outs . length )
269309 this . outs . forEach ( function ( txOut ) {
270- writeUInt64 ( txOut . value )
310+ if ( ! txOut . valueBuffer ) {
311+ writeUInt64 ( txOut . value )
312+ } else {
313+ writeSlice ( txOut . valueBuffer )
314+ }
315+
271316 writeVarInt ( txOut . script . buffer . length )
272317 writeSlice ( txOut . script . buffer )
273318 } )
0 commit comments