@ -97,8 +97,8 @@ var FEE_PER_1000B_SAT = parseInt(0.0001 * util.COIN);
// ```
function TransactionBuilder ( opts ) {
opts = opts || { } ;
this . lockTime = opts . lockTime || 0 ;
opts = opts || { } ;
this . lockTime = opts . lockTime || 0 ;
this . spendUnconfirmed = opts . spendUnconfirmed || false ;
if ( opts . fee || opts . feeSat ) {
@ -107,9 +107,9 @@ function TransactionBuilder(opts) {
this . remainderOut = opts . remainderOut ;
this . signhash = opts . signhash || Transaction . SIGHASH_ALL ;
this . tx = { } ;
this . inputsSigned = 0 ;
this . signaturesAdded = 0 ;
this . tx = { } ;
this . inputsSigned = 0 ;
this . signaturesAdded = 0 ;
return this ;
}
@ -119,10 +119,10 @@ TransactionBuilder.FEE_PER_1000B_SAT = FEE_PER_1000B_SAT;
TransactionBuilder . _ scriptForPubkeys = function ( out ) {
var l = out . pubkeys . length ;
var pubKeyBuf = [ ] ;
var pubKeyBuf = [ ] ;
for ( var i = 0 ; i < l ; i ++ ) {
pubKeyBuf . push ( new Buffer ( out . pubkeys [ i ] , 'hex' ) ) ;
for ( var i = 0 ; i < l ; i ++ ) {
pubKeyBuf . push ( new Buffer ( out . pubkeys [ i ] , 'hex' ) ) ;
}
return Script . createMultisig ( out . nreq , pubKeyBuf ) ;
@ -143,7 +143,7 @@ TransactionBuilder._scriptForOut = function(out) {
TransactionBuilder . infoForP2sh = function ( opts , networkName ) {
var script = this . _ scriptForOut ( opts ) ;
var hash = util . sha256ripe160 ( script . getBuffer ( ) ) ;
var hash = util . sha256ripe160 ( script . getBuffer ( ) ) ;
var version = networkName === 'testnet' ?
networks . testnet . P2SHVersion : networks . livenet . P2SHVersion ;
@ -187,14 +187,14 @@ TransactionBuilder.prototype._setInputMap = function() {
var l = this . selectedUtxos . length ;
for ( var i = 0 ; i < l ; i ++ ) {
var utxo = this . selectedUtxos [ i ] ;
var scriptBuf = new Buffer ( utxo . scriptPubKey , 'hex' ) ;
var scriptPubKey = new Script ( scriptBuf ) ;
var scriptType = scriptPubKey . classify ( ) ;
var utxo = this . selectedUtxos [ i ] ;
var scriptBuf = new Buffer ( utxo . scriptPubKey , 'hex' ) ;
var scriptPubKey = new Script ( scriptBuf ) ;
var scriptType = scriptPubKey . classify ( ) ;
if ( scriptType === Script . TX_UNKNOWN )
throw new Error ( 'unkown output type at:' + i +
' Type:' + scriptPubKey . getRawOutType ( ) ) ;
' Type:' + scriptPubKey . getRawOutType ( ) ) ;
inputMap . push ( {
address : utxo . address ,
@ -218,10 +218,10 @@ TransactionBuilder.prototype.getSelectedUnspent = function() {
} ;
/ * _ s e l e c t U n s p e n t
* TODO ( ? ) : sort sel ( at the end ) and check is some inputs can be avoided .
* If the initial utxos are sorted , this step would be necesary only if
* utxos were selected from different minConfirmationSteps .
* /
* TODO ( ? ) : sort sel ( at the end ) and check is some inputs can be avoided .
* If the initial utxos are sorted , this step would be necesary only if
* utxos were selected from different minConfirmationSteps .
* /
TransactionBuilder . prototype . _ selectUnspent = function ( neededAmountSat ) {
@ -231,11 +231,11 @@ TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
var minConfirmationSteps = [ 6 , 1 ] ;
if ( this . spendUnconfirmed ) minConfirmationSteps . push ( 0 ) ;
var sel = [ ] ,
totalSat = bignum ( 0 ) ,
fulfill = false ,
var sel = [ ] ,
totalSat = bignum ( 0 ) ,
fulfill = false ,
maxConfirmations = null ,
l = this . utxos . length ;
l = this . utxos . length ;
do {
var minConfirmations = minConfirmationSteps . shift ( ) ;
@ -259,7 +259,7 @@ TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
if ( ! fulfill )
throw new Error ( 'not enough unspent tx outputs to fulfill totalNeededAmount [SAT]:' +
neededAmountSat ) ;
neededAmountSat ) ;
this . selectedUtxos = sel ;
this . _ setInputMap ( ) ;
@ -271,7 +271,7 @@ TransactionBuilder.prototype._setInputs = function(txobj) {
var l = ins . length ;
var valueInSat = bignum ( 0 ) ;
txobj . ins = [ ] ;
txobj . ins = [ ] ;
for ( var i = 0 ; i < l ; i ++ ) {
valueInSat = valueInSat . add ( util . parseValue ( ins [ i ] . amount ) ) ;
@ -294,7 +294,7 @@ TransactionBuilder.prototype._setInputs = function(txobj) {
} ;
TransactionBuilder . prototype . _ setFee = function ( feeSat ) {
if ( typeof this . valueOutSat === 'undefined' )
if ( typeof this . valueOutSat === 'undefined' )
throw new Error ( 'valueOutSat undefined' ) ;
@ -312,13 +312,13 @@ TransactionBuilder.prototype._setFee = function(feeSat) {
TransactionBuilder . prototype . _ setRemainder = function ( txobj , remainderIndex ) {
if ( typeof this . valueInSat === 'undefined' ||
typeof this . valueOutSat === 'undefined' )
if ( typeof this . valueInSat === 'undefined' ||
typeof this . valueOutSat === 'undefined' )
throw new Error ( 'valueInSat / valueOutSat undefined' ) ;
/* add remainder (without modifying outs[]) */
var remainderSat = this . valueInSat . sub ( this . valueOutSat ) . sub ( this . feeSat ) ;
var l = txobj . outs . length ;
var l = txobj . outs . length ;
this . remainderSat = bignum ( 0 ) ;
/*remove old remainder? */
@ -344,7 +344,8 @@ TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
TransactionBuilder . prototype . _ setFeeAndRemainder = function ( txobj ) {
/* starting size estimation */
var size = 500 , maxSizeK , remainderIndex = txobj . outs . length ;
var size = 500 ,
maxSizeK , remainderIndex = txobj . outs . length ;
do {
/* based on https://en.bitcoin.it/wiki/Transaction_fees */
maxSizeK = parseInt ( size / 1000 ) + 1 ;
@ -355,11 +356,11 @@ TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
var neededAmountSat = this . valueOutSat . add ( feeSat ) ;
this . _ selectUnspent ( neededAmountSat )
. _ setInputs ( txobj )
. _ setFee ( feeSat )
. _ setRemainder ( txobj , remainderIndex ) ;
. _ setInputs ( txobj )
. _ setFee ( feeSat )
. _ setRemainder ( txobj , remainderIndex ) ;
size = new Transaction ( txobj ) . getSize ( ) ;
} while ( size > ( maxSizeK + 1 ) * 1000 ) ;
return this ;
@ -383,13 +384,13 @@ TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
TransactionBuilder . prototype . setOutputs = function ( outs ) {
var valueOutSat = bignum ( 0 ) ;
var txobj = { } ;
txobj . version = 1 ;
txobj . lock_time = this . lockTime || 0 ;
txobj . ins = [ ] ;
var txobj = { } ;
txobj . version = 1 ;
txobj . lock_time = this . lockTime || 0 ;
txobj . ins = [ ] ;
txobj . outs = [ ] ;
var l = outs . length ;
var l = outs . length ;
for ( var i = 0 ; i < l ; i ++ ) {
var amountSat = outs [ i ] . amountSat || util . parseValue ( outs [ i ] . amount ) ;
var value = util . bigIntToValue ( amountSat ) ;
@ -422,13 +423,15 @@ TransactionBuilder._mapKeys = function(keys) {
if ( typeof k === 'string' ) {
var pk = new PrivateKey ( k ) ;
wk = new WalletKey ( { network : pk . network ( ) } ) ;
wk . fromObj ( { priv : k } ) ;
}
else if ( k instanceof WalletKey ) {
wk = new WalletKey ( {
network : pk . network ( )
} ) ;
wk . fromObj ( {
priv : k
} ) ;
} else if ( k instanceof WalletKey ) {
wk = k ;
}
else {
} else {
throw new Error ( 'argument must be an array of strings (WIF format) or WalletKey objects' ) ;
}
walletKeyMap [ wk . storeObj ( ) . addr ] = wk ;
@ -437,30 +440,31 @@ TransactionBuilder._mapKeys = function(keys) {
} ;
TransactionBuilder . _ signHashAndVerify = function ( wk , txSigHash ) {
var triesLeft = 10 , sigRaw ;
var triesLeft = 10 ,
sigRaw ;
do {
sigRaw = wk . privKey . signSync ( txSigHash ) ;
} while ( wk . privKey . verifySignatureSync ( txSigHash , sigRaw ) === false &&
triesLeft -- ) ;
triesLeft -- ) ;
if ( triesLeft < 0 )
if ( triesLeft < 0 )
throw new Error ( 'could not sign input: verification failed' ) ;
return sigRaw ;
} ;
TransactionBuilder . prototype . _ checkTx = function ( ) {
if ( ! this . tx || ! this . tx . ins . length || ! this . tx . outs . length )
if ( ! this . tx || ! this . tx . ins . length || ! this . tx . outs . length )
throw new Error ( 'tx is not defined' ) ;
} ;
TransactionBuilder . prototype . _ multiFindKey = function ( walletKeyMap , pubKeyHash ) {
TransactionBuilder . prototype . _ multiFindKey = function ( walletKeyMap , pubKeyHash ) {
var wk ;
[ networks . livenet , networks . testnet ] . forEach ( function ( n ) {
[ n . addressVersion , n . P2SHVersion ] . forEach ( function ( v ) {
var a = new Address ( v , pubKeyHash ) ;
[ networks . livenet , networks . testnet ] . forEach ( function ( n ) {
[ n . addressVersion , n . P2SHVersion ] . forEach ( function ( v ) {
var a = new Address ( v , pubKeyHash ) ;
if ( ! wk && walletKeyMap [ a ] ) {
wk = walletKeyMap [ a ] ;
}
@ -474,14 +478,12 @@ TransactionBuilder.prototype._findWalletKey = function(walletKeyMap, input) {
var wk ;
if ( input . address ) {
wk = walletKeyMap [ input . address ] ;
}
else if ( input . pubKeyHash ) {
wk = this . _ multiFindKey ( walletKeyMap , input . pubKeyHash ) ;
}
else if ( input . pubKeyBuf ) {
wk = walletKeyMap [ input . address ] ;
} else if ( input . pubKeyHash ) {
wk = this . _ multiFindKey ( walletKeyMap , input . pubKeyHash ) ;
} else if ( input . pubKeyBuf ) {
var pubKeyHash = util . sha256ripe160 ( input . pubKeyBuf ) ;
wk = this . _ multiFindKey ( walletKeyMap , pubKeyHash ) ;
wk = this . _ multiFindKey ( walletKeyMap , pubKeyHash ) ;
} else {
throw new Error ( 'no infomation at input to find keys' ) ;
}
@ -491,37 +493,45 @@ TransactionBuilder.prototype._findWalletKey = function(walletKeyMap, input) {
TransactionBuilder . prototype . _ signPubKey = function ( walletKeyMap , input , txSigHash ) {
if ( this . tx . ins [ input . i ] . s . length > 0 ) return { } ;
var wk = this . _ findWalletKey ( walletKeyMap , input ) ;
var wk = this . _ findWalletKey ( walletKeyMap , input ) ;
if ( ! wk ) return ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigType = new Buffer ( 1 ) ;
sigType [ 0 ] = this . signhash ;
var sig = Buffer . concat ( [ sigRaw , sigType ] ) ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigType = new Buffer ( 1 ) ;
sigType [ 0 ] = this . signhash ;
var sig = Buffer . concat ( [ sigRaw , sigType ] ) ;
var scriptSig = new Script ( ) ;
scriptSig . chunks . push ( sig ) ;
scriptSig . updateBuffer ( ) ;
return { inputFullySigned : true , signaturesAdded : 1 , script : scriptSig . getBuffer ( ) } ;
return {
inputFullySigned : true ,
signaturesAdded : 1 ,
script : scriptSig . getBuffer ( )
} ;
} ;
TransactionBuilder . prototype . _ signPubKeyHash = function ( walletKeyMap , input , txSigHash ) {
if ( this . tx . ins [ input . i ] . s . length > 0 ) return { } ;
var wk = this . _ findWalletKey ( walletKeyMap , input ) ;
var wk = this . _ findWalletKey ( walletKeyMap , input ) ;
if ( ! wk ) return ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigType = new Buffer ( 1 ) ;
sigType [ 0 ] = this . signhash ;
var sig = Buffer . concat ( [ sigRaw , sigType ] ) ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigType = new Buffer ( 1 ) ;
sigType [ 0 ] = this . signhash ;
var sig = Buffer . concat ( [ sigRaw , sigType ] ) ;
var scriptSig = new Script ( ) ;
scriptSig . chunks . push ( sig ) ;
scriptSig . chunks . push ( wk . privKey . public ) ;
scriptSig . updateBuffer ( ) ;
return { inputFullySigned : true , signaturesAdded : 1 , script : scriptSig . getBuffer ( ) } ;
return {
inputFullySigned : true ,
signaturesAdded : 1 ,
script : scriptSig . getBuffer ( )
} ;
} ;
/ * F O R T E S T I N G
@ -537,13 +547,13 @@ var _dumpChunks = function (scriptSig, label) {
TransactionBuilder . prototype . _ chunkSignedWithKey = function ( scriptSig , txSigHash , publicKey ) {
var ret ;
var k = new Key ( ) ;
k . public = publicKey ;
k . public = publicKey ;
for ( var i = 1 ; i <= scriptSig . countSignatures ( ) ; i ++ ) {
for ( var i = 1 ; i <= scriptSig . countSignatures ( ) ; i ++ ) {
var chunk = scriptSig . chunks [ i ] ;
var sigRaw = new Buffer ( chunk . slice ( 0 , chunk . length - 1 ) ) ;
if ( k . verifySignatureSync ( txSigHash , sigRaw ) ) {
ret = chunk ;
var sigRaw = new Buffer ( chunk . slice ( 0 , chunk . length - 1 ) ) ;
if ( k . verifySignatureSync ( txSigHash , sigRaw ) ) {
ret = chunk ;
}
}
return ret ;
@ -551,10 +561,10 @@ TransactionBuilder.prototype._chunkSignedWithKey = function(scriptSig, txSigHash
TransactionBuilder . prototype . _ getSignatureOrder = function ( sigPrio , sigRaw , txSigHash , pubkeys ) {
var l = pubkeys . length ;
for ( var j = 0 ; j < l ; j ++ ) {
var l = pubkeys . length ;
for ( var j = 0 ; j < l ; j ++ ) {
var k = new Key ( ) ;
k . public = new Buffer ( pubkeys [ j ] , 'hex' ) ;
k . public = new Buffer ( pubkeys [ j ] , 'hex' ) ;
if ( k . verifySignatureSync ( txSigHash , sigRaw ) )
break ;
}
@ -563,17 +573,17 @@ TransactionBuilder.prototype._getSignatureOrder = function(sigPrio, sigRaw, txSi
TransactionBuilder . prototype . _ getNewSignatureOrder = function ( sigPrio , scriptSig , txSigHash , pubkeys ) {
var iPrio ;
for ( var i = 1 ; i <= scriptSig . countSignatures ( ) ; i ++ ) {
for ( var i = 1 ; i <= scriptSig . countSignatures ( ) ; i ++ ) {
var chunk = scriptSig . chunks [ i ] ;
var sigRaw = new Buffer ( chunk . slice ( 0 , chunk . length - 1 ) ) ;
var sigRaw = new Buffer ( chunk . slice ( 0 , chunk . length - 1 ) ) ;
iPrio = this . _ getSignatureOrder ( sigPrio , sigRaw , txSigHash , pubkeys ) ;
if ( sigPrio <= iPrio ) break ;
}
return ( sigPrio === iPrio ? - 1 : i - 1 ) ;
return ( sigPrio === iPrio ? - 1 : i - 1 ) ;
} ;
TransactionBuilder . prototype . _ chunkIsEmpty = function ( chunk ) {
return chunk === 0 || // when serializing and back, EMPTY_BUFFER becomes 0
return chunk === 0 || // when serializing and back, EMPTY_BUFFER becomes 0
buffertools . compare ( chunk , util . EMPTY_BUFFER ) === 0 ;
} ;
@ -593,16 +603,16 @@ TransactionBuilder.prototype._updateMultiSig = function(sigPrio, wk, scriptSig,
return null ;
// Create signature
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigType = new Buffer ( 1 ) ;
sigType [ 0 ] = this . signhash ;
var sig = Buffer . concat ( [ sigRaw , sigType ] ) ;
sigType [ 0 ] = this . signhash ;
var sig = Buffer . concat ( [ sigRaw , sigType ] ) ;
// Add signature
var order = this . _ getNewSignatureOrder ( sigPrio , scriptSig , txSigHash , pubkeys ) ;
scriptSig . chunks . splice ( order + 1 , 0 , sig ) ;
var order = this . _ getNewSignatureOrder ( sigPrio , scriptSig , txSigHash , pubkeys ) ;
scriptSig . chunks . splice ( order + 1 , 0 , sig ) ;
scriptSig . updateBuffer ( ) ;
wasUpdated = true ;
wasUpdated = true ;
return wasUpdated ? scriptSig : null ;
} ;
@ -610,15 +620,17 @@ TransactionBuilder.prototype._updateMultiSig = function(sigPrio, wk, scriptSig,
TransactionBuilder . prototype . _ signMultiSig = function ( walletKeyMap , input , txSigHash ) {
var pubkeys = input . scriptPubKey . capture ( ) ,
nreq = input . scriptPubKey . chunks [ 0 ] - 80 , //see OP_2-OP_16
nreq = input . scriptPubKey . chunks [ 0 ] - 80 , //see OP_2-OP_16
l = pubkeys . length ,
originalScriptBuf = this . tx . ins [ input . i ] . s ;
var scriptSig = new Script ( originalScriptBuf ) ;
var scriptSig = new Script ( originalScriptBuf ) ;
var signaturesAdded = 0 ;
for ( var j = 0 ; j < l && scriptSig . countSignatures ( ) < nreq ; j ++ ) {
var wk = this . _ findWalletKey ( walletKeyMap , { pubKeyBuf : pubkeys [ j ] } ) ;
for ( var j = 0 ; j < l && scriptSig . countSignatures ( ) < nreq ; j ++ ) {
var wk = this . _ findWalletKey ( walletKeyMap , {
pubKeyBuf : pubkeys [ j ]
} ) ;
if ( ! wk ) continue ;
var newScriptSig = this . _ updateMultiSig ( j , wk , scriptSig , txSigHash , pubkeys ) ;
@ -629,22 +641,22 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
}
var ret = {
inputFullySigned : scriptSig . countSignatures ( ) === nreq ,
inputFullySigned : scriptSig . countSignatures ( ) === nreq ,
signaturesAdded : signaturesAdded ,
script : scriptSig . getBuffer ( ) ,
} ;
return ret ;
} ;
var fnToSign = { } ;
TransactionBuilder . prototype . _ scriptIsAppended = function ( script , scriptToAddBuf ) {
var len = script . chunks . length ;
if ( script . chunks [ len - 1 ] === undefined )
if ( script . chunks [ len - 1 ] === undefined )
return false ;
if ( typeof script . chunks [ len - 1 ] === 'number' )
if ( typeof script . chunks [ len - 1 ] === 'number' )
return false ;
if ( buffertools . compare ( script . chunks [ len - 1 ] , scriptToAddBuf ) !== 0 )
if ( buffertools . compare ( script . chunks [ len - 1 ] , scriptToAddBuf ) !== 0 )
return false ;
return true ;
@ -659,17 +671,17 @@ TransactionBuilder.prototype._addScript = function(scriptBuf, scriptToAddBuf) {
}
return s . getBuffer ( ) ;
} ;
TransactionBuilder . prototype . _ getInputForP2sh = function ( script , index ) {
var scriptType = script . classify ( ) ;
/* pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys. */
var pubKeyHash ;
switch ( scriptType ) {
switch ( scriptType ) {
case Script . TX_PUBKEYHASH :
pubKeyHash = script . captureOne ( ) ;
break ;
case Script . TX_PUBKEY :
var chunk = script . captureOne ( ) ;
var chunk = script . captureOne ( ) ;
pubKeyHash = util . sha256ripe160 ( chunk ) ;
}
@ -689,16 +701,16 @@ TransactionBuilder.prototype._p2shInput = function(input) {
var scriptHex = this . hashToScriptMap [ input . address ] ;
if ( ! scriptHex ) return ;
var scriptBuf = new Buffer ( scriptHex , 'hex' ) ;
var script = new Script ( scriptBuf ) ;
var scriptType = script . classify ( ) ;
var scriptBuf = new Buffer ( scriptHex , 'hex' ) ;
var script = new Script ( scriptBuf ) ;
var scriptType = script . classify ( ) ;
if ( ! fnToSign [ scriptType ] || scriptType === Script . TX_SCRIPTHASH )
throw new Error ( 'dont know how to sign p2sh script type:' + script . getRawOutType ( ) ) ;
throw new Error ( 'dont know how to sign p2sh script type:' + script . getRawOutType ( ) ) ;
return {
input : this . _ getInputForP2sh ( script , input . i ) ,
txSigHash : this . tx . hashForSignature ( script , input . i , this . signhash ) ,
txSigHash : this . tx . hashForSignature ( script , input . i , this . signhash ) ,
scriptType : script . classify ( ) ,
scriptBuf : scriptBuf ,
} ;
@ -706,9 +718,9 @@ TransactionBuilder.prototype._p2shInput = function(input) {
TransactionBuilder . prototype . _ signScriptHash = function ( walletKeyMap , input , txSigHash ) {
var p2sh = this . _ p2shInput ( input ) ;
var p2sh = this . _ p2shInput ( input ) ;
var ret = fnToSign [ p2sh . scriptType ] . call ( this , walletKeyMap , p2sh . input , p2sh . txSigHash ) ;
var ret = fnToSign [ p2sh . scriptType ] . call ( this , walletKeyMap , p2sh . input , p2sh . txSigHash ) ;
if ( ret && ret . script && ret . signaturesAdded ) {
ret . script = this . _ addScript ( ret . script , p2sh . scriptBuf ) ;
}
@ -716,8 +728,8 @@ TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txS
} ;
fnToSign [ Script . TX_PUBKEYHASH ] = TransactionBuilder . prototype . _ signPubKeyHash ;
fnToSign [ Script . TX_PUBKEY ] = TransactionBuilder . prototype . _ signPubKey ;
fnToSign [ Script . TX_MULTISIG ] = TransactionBuilder . prototype . _ signMultiSig ;
fnToSign [ Script . TX_PUBKEY ] = TransactionBuilder . prototype . _ signPubKey ;
fnToSign [ Script . TX_MULTISIG ] = TransactionBuilder . prototype . _ signMultiSig ;
fnToSign [ Script . TX_SCRIPTHASH ] = TransactionBuilder . prototype . _ signScriptHash ;
// sign
@ -736,10 +748,10 @@ fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash;
//
TransactionBuilder . prototype . sign = function ( keys ) {
this . _ checkTx ( ) ;
var tx = this . tx ,
ins = tx . ins ,
l = ins . length ,
walletKeyMap = TransactionBuilder . _ mapKeys ( keys ) ;
var tx = this . tx ,
ins = tx . ins ,
l = ins . length ,
walletKeyMap = TransactionBuilder . _ mapKeys ( keys ) ;
for ( var i = 0 ; i < l ; i ++ ) {
var input = this . inputMap [ i ] ;
@ -751,7 +763,7 @@ TransactionBuilder.prototype.sign = function(keys) {
if ( ret && ret . script ) {
tx . ins [ i ] . s = ret . script ;
if ( ret . inputFullySigned ) this . inputsSigned ++ ;
if ( ret . signaturesAdded ) this . signaturesAdded += ret . signaturesAdded ;
if ( ret . signaturesAdded ) this . signaturesAdded += ret . signaturesAdded ;
}
}
return this ;
@ -764,7 +776,7 @@ TransactionBuilder.prototype.sign = function(keys) {
// for generate the input for this call.
//
TransactionBuilder . prototype . setHashToScriptMap = function ( hashToScriptMap ) {
this . hashToScriptMap = hashToScriptMap ;
this . hashToScriptMap = hashToScriptMap ;
return this ;
} ;
@ -792,23 +804,23 @@ TransactionBuilder.prototype.build = function() {
// See `.fromObj`
//
TransactionBuilder . prototype . toObj = function ( ) {
var data = {
valueInSat : this . valueInSat . toString ( ) ,
valueOutSat : this . valueOutSat . toString ( ) ,
feeSat : this . feeSat . toString ( ) ,
remainderSat : this . remainderSat . toString ( ) ,
var data = {
valueInSat : this . valueInSat . toString ( ) ,
valueOutSat : this . valueOutSat . toString ( ) ,
feeSat : this . feeSat . toString ( ) ,
remainderSat : this . remainderSat . toString ( ) ,
hashToScriptMap : this . hashToScriptMap ,
selectedUtxos : this . selectedUtxos ,
hashToScriptMap : this . hashToScriptMap ,
selectedUtxos : this . selectedUtxos ,
inputsSigned : this . inputsSigned ,
signaturesAdded : this . signaturesAdded ,
inputsSigned : this . inputsSigned ,
signaturesAdded : this . signaturesAdded ,
signhash : this . signhash ,
spendUnconfirmed : this . spendUnconfirmed ,
signhash : this . signhash ,
spendUnconfirmed : this . spendUnconfirmed ,
} ;
if ( this . tx ) {
data . tx = this . tx . serialize ( ) . toString ( 'hex' ) ;
data . tx = this . tx . serialize ( ) . toString ( 'hex' ) ;
}
return data ;
} ;
@ -821,18 +833,18 @@ TransactionBuilder.prototype.toObj = function() {
TransactionBuilder . fromObj = function ( data ) {
var b = new TransactionBuilder ( ) ;
b . valueInSat = data . valueInSat . toString ( ) ;
b . valueOutSat = data . valueOutSat . toString ( ) ;
b . feeSat = data . feeSat . toString ( ) ;
b . remainderSat = data . remainderSat . toString ( ) ;
b . valueInSat = data . valueInSat . toString ( ) ;
b . valueOutSat = data . valueOutSat . toString ( ) ;
b . feeSat = data . feeSat . toString ( ) ;
b . remainderSat = data . remainderSat . toString ( ) ;
b . hashToScriptMap = data . hashToScriptMap ;
b . selectedUtxos = data . selectedUtxos ;
b . hashToScriptMap = data . hashToScriptMap ;
b . selectedUtxos = data . selectedUtxos ;
b . inputsSigned = data . inputsSigned ;
b . signaturesAdded = data . signaturesAdded ;
b . inputsSigned = data . inputsSigned ;
b . signaturesAdded = data . signaturesAdded ;
b . signhash = data . signhash ;
b . signhash = data . signhash ;
b . spendUnconfirmed = data . spendUnconfirmed ;
b . _ setInputMap ( ) ;
@ -840,7 +852,7 @@ TransactionBuilder.fromObj = function(data) {
if ( data . tx ) {
// Tx may have signatures, that are not on txobj
var t = new Transaction ( ) ;
t . parse ( new Buffer ( data . tx , 'hex' ) ) ;
t . parse ( new Buffer ( data . tx , 'hex' ) ) ;
b . tx = t ;
}
return b ;
@ -848,79 +860,80 @@ TransactionBuilder.fromObj = function(data) {
TransactionBuilder . prototype . _ checkMergeability = function ( b ) {
var self = this ;
var self = this ;
// Builder should have the same params
[ 'valueInSat' , 'valueOutSat' , 'feeSat' , 'remainderSat' , 'signhash' , 'spendUnconfirmed' ]
. forEach ( function ( k ) {
. forEach ( function ( k ) {
if ( self [ k ] . toString ( ) !== b [ k ] . toString ( ) ) {
throw new Error ( 'mismatch at TransactionBuilder match: '
+ k + ': ' + self [ k ] + ' vs. ' + b [ k ] ) ;
}
} ) ;
if ( self [ k ] . toString ( ) !== b [ k ] . toString ( ) ) {
throw new Error ( 'mismatch at TransactionBuilder match: ' + k + ': ' + self [ k ] + ' vs. ' + b [ k ] ) ;
}
} ) ;
if ( self . hashToScriptMap ) {
var err = 0 ;
if ( ! b . hashToScriptMap ) err = 1 ;
if ( ! b . hashToScriptMap ) err = 1 ;
Object . keys ( self . hashToScriptMap ) . forEach ( function ( k ) {
if ( ! b . hashToScriptMap [ k ] ) err = 1 ;
if ( self . hashToScriptMap [ k ] !== b . hashToScriptMap [ k ] ) err = 1 ;
if ( ! b . hashToScriptMap [ k ] ) err = 1 ;
if ( self . hashToScriptMap [ k ] !== b . hashToScriptMap [ k ] ) err = 1 ;
} ) ;
if ( err )
throw new Error ( 'mismatch at TransactionBuilder hashToScriptMap' ) ;
}
var err = 0 , i = 0 ; ;
var err = 0 ,
i = 0 ; ;
self . selectedUtxos . forEach ( function ( u ) {
if ( ! err ) {
var v = b . selectedUtxos [ i ++ ] ;
if ( ! v ) err = 1 ;
var v = b . selectedUtxos [ i ++ ] ;
if ( ! v ) err = 1 ;
// confirmations could differ
[ 'address' , 'hash' , 'scriptPubKey' , 'vout' , 'amount' ] . forEach ( function ( k ) {
if ( u [ k ] !== v [ k ] )
err = k ;
err = k ;
} ) ;
}
} ) ;
if ( err )
throw new Error ( 'mismatch at TransactionBuilder selectedUtxos #' + i - 1 + ' Key:' + err ) ;
throw new Error ( 'mismatch at TransactionBuilder selectedUtxos #' + i - 1 + ' Key:' + err ) ;
err = 0 ; i = 0 ; ;
err = 0 ;
i = 0 ; ;
self . inputMap . forEach ( function ( u ) {
if ( ! err ) {
var v = b . inputMap [ i ++ ] ;
if ( ! v ) err = 1 ;
var v = b . inputMap [ i ++ ] ;
if ( ! v ) err = 1 ;
// confirmations could differ
[ 'address' , 'scriptType' , 'scriptPubKey' , 'i' ] . forEach ( function ( k ) {
if ( u [ k ] . toString ( ) !== v [ k ] . toString ( ) )
err = k ;
err = k ;
} ) ;
}
} ) ;
if ( err )
throw new Error ( 'mismatch at TransactionBuilder inputMap #' + i - 1 + ' Key:' + err ) ;
throw new Error ( 'mismatch at TransactionBuilder inputMap #' + i - 1 + ' Key:' + err ) ;
} ;
// TODO this could be on Script class
TransactionBuilder . prototype . _ mergeInputSigP2sh = function ( input , s0 , s1 ) {
var p2sh = this . _ p2shInput ( input ) ;
TransactionBuilder . prototype . _ mergeInputSigP2sh = function ( input , s0 , s1 ) {
var p2sh = this . _ p2shInput ( input ) ;
var redeemScript = new Script ( p2sh . scriptBuf ) ;
var pubkeys = redeemScript . capture ( ) ;
// Look for differences
var s0keys = { } ;
var l = pubkeys . length ;
for ( var j = 0 ; j < l ; j ++ ) {
if ( this . _ chunkSignedWithKey ( s0 , p2sh . txSigHash , pubkeys [ j ] ) )
for ( var j = 0 ; j < l ; j ++ ) {
if ( this . _ chunkSignedWithKey ( s0 , p2sh . txSigHash , pubkeys [ j ] ) )
s0keys [ pubkeys [ j ] . toString ( 'hex' ) ] = 1 ;
}
var diff = [ ] ;
for ( var j = 0 ; j < l ; j ++ ) {
for ( var j = 0 ; j < l ; j ++ ) {
var chunk = this . _ chunkSignedWithKey ( s1 , p2sh . txSigHash , pubkeys [ j ] ) ;
var pubHex = pubkeys [ j ] . toString ( 'hex' ) ;
if ( chunk && ! s0keys [ pubHex ] ) {
@ -933,10 +946,10 @@ TransactionBuilder.prototype._mergeInputSigP2sh = function(input,s0,s1) {
}
// Add signatures
for ( var j in diff ) {
for ( var j in diff ) {
var newSig = diff [ j ] ;
var order = this . _ getNewSignatureOrder ( newSig . prio , s0 , p2sh . txSigHash , pubkeys ) ;
s0 . chunks . splice ( order + 1 , 0 , newSig . chunk ) ;
var order = this . _ getNewSignatureOrder ( newSig . prio , s0 , p2sh . txSigHash , pubkeys ) ;
s0 . chunks . splice ( order + 1 , 0 , newSig . chunk ) ;
this . signaturesAdded ++ ;
}
s0 . updateBuffer ( ) ;
@ -945,7 +958,7 @@ TransactionBuilder.prototype._mergeInputSigP2sh = function(input,s0,s1) {
// TODO this could be on Script class
TransactionBuilder . prototype . _ mergeInputSig = function ( index , s0buf , s1buf ) {
if ( buffertools . compare ( s0buf , s1buf ) === 0 )
if ( buffertools . compare ( s0buf , s1buf ) === 0 )
return s0buf ;
var s0 = new Script ( s0buf ) ;
@ -954,53 +967,52 @@ TransactionBuilder.prototype._mergeInputSig = function(index, s0buf, s1buf) {
var l1 = s1 . chunks . length ;
var s0map = { } ;
if ( l0 && l1 && ( ( l0 < 2 && l1 > 2 ) || ( l1 < 2 && l0 > 2 ) ) )
if ( l0 && l1 && ( ( l0 < 2 && l1 > 2 ) || ( l1 < 2 && l0 > 2 ) ) )
throw new Error ( 'TX sig types mismatch in merge' ) ;
if ( ( ! l0 && ! l1 ) || ( l0 && ! l1 ) || ( ! l0 && l1 ) )
if ( ( ! l0 && ! l1 ) || ( l0 && ! l1 ) || ( ! l0 && l1 ) )
return s1buf ;
// Get the pubkeys
var input = this . inputMap [ index ] ;
var type = input . scriptPubKey . classify ( ) ;
var type = input . scriptPubKey . classify ( ) ;
//p2pubkey or p2pubkeyhash
if ( type === Script . TX_PUBKEYHASH || type === Script . TX_PUBKEY ) {
log . debug ( 'Merging two signed inputs type:' +
input . scriptPubKey . getRawOutType ( ) + '. Signatures differs. Using the first version.' ) ;
return s0buf ;
}
else if ( type !== Script . TX_SCRIPTHASH ) {
} else if ( type !== Script . TX_SCRIPTHASH ) {
// No support for normal multisig or strange txs.
throw new Error ( 'Script type:' + input . scriptPubKey . getRawOutType ( ) + 'not supported at #merge' ) ;
throw new Error ( 'Script type:' + input . scriptPubKey . getRawOutType ( ) + 'not supported at #merge' ) ;
}
return this . _ mergeInputSigP2sh ( input , s0 , s1 ) ;
return this . _ mergeInputSigP2sh ( input , s0 , s1 ) ;
} ;
// TODO this could be on Transaction class
TransactionBuilder . prototype . _ mergeTx = function ( tx ) {
var v0 = this . tx ;
var v1 = tx ;
var v0 = this . tx ;
var v1 = tx ;
var l = v0 . ins . length ;
if ( l !== v1 . ins . length )
throw new Error ( 'TX in length mismatch in merge' ) ;
var l = v0 . ins . length ;
if ( l !== v1 . ins . length )
throw new Error ( 'TX in length mismatch in merge' ) ;
this . inputsSigned = 0 ;
for ( var i = 0 ; i < l ; i ++ ) {
var i0 = v0 . ins [ i ] ;
var i1 = v1 . ins [ i ] ;
this . inputsSigned = 0 ;
for ( var i = 0 ; i < l ; i ++ ) {
var i0 = v0 . ins [ i ] ;
var i1 = v1 . ins [ i ] ;
if ( i0 . q !== i1 . q )
throw new Error ( 'TX sequence ins mismatch in merge. Input:' , i ) ;
if ( i0 . q !== i1 . q )
throw new Error ( 'TX sequence ins mismatch in merge. Input:' , i ) ;
if ( buffertools . compare ( i0 . o , i1 . o ) !== 0 )
throw new Error ( 'TX .o in mismatch in merge. Input:' , i ) ;
if ( buffertools . compare ( i0 . o , i1 . o ) !== 0 )
throw new Error ( 'TX .o in mismatch in merge. Input:' , i ) ;
i0 . s = this . _ mergeInputSig ( i , i0 . s , i1 . s ) ;
i0 . s = this . _ mergeInputSig ( i , i0 . s , i1 . s ) ;
if ( v0 . isInputComplete ( i ) ) this . inputsSigned ++ ;
}
if ( v0 . isInputComplete ( i ) ) this . inputsSigned ++ ;
}
} ;
// merge
@ -1013,11 +1025,10 @@ TransactionBuilder.prototype.merge = function(b) {
// Does this tX have any signature already?
if ( this . tx || b . tx ) {
if ( this . tx . getNormalizedHash ( ) . toString ( 'hex' )
!== b . tx . getNormalizedHash ( ) . toString ( 'hex' ) )
if ( this . tx . getNormalizedHash ( ) . toString ( 'hex' ) !== b . tx . getNormalizedHash ( ) . toString ( 'hex' ) )
throw new Error ( 'mismatch at TransactionBuilder NTXID' ) ;
this . _ mergeTx ( b . tx ) ;
this . _ mergeTx ( b . tx ) ;
}
} ;