@ -115,12 +115,12 @@ function TransactionBuilder(opts) {
}
}
/ *
/ *
* _ scriptForAddress
* scriptForAddress
*
*
* Returns a scriptPubKey for the given address type
* Returns a scriptPubKey for the given address type
* /
* /
TransactionBuilder . _ scriptForAddress = function ( addressString ) {
TransactionBuilder . scriptForAddress = function ( addressString ) {
var livenet = networks . livenet ;
var livenet = networks . livenet ;
var testnet = networks . testnet ;
var testnet = networks . testnet ;
@ -154,7 +154,7 @@ TransactionBuilder._scriptForPubkeys = function(out) {
TransactionBuilder . _ scriptForOut = function ( out ) {
TransactionBuilder . _ scriptForOut = function ( out ) {
var ret ;
var ret ;
if ( out . address )
if ( out . address )
ret = this . _ scriptForAddress ( out . address ) ;
ret = this . scriptForAddress ( out . address ) ;
else if ( out . pubkeys || out . nreq || out . nreq > 1 )
else if ( out . pubkeys || out . nreq || out . nreq > 1 )
ret = this . _ scriptForPubkeys ( out ) ;
ret = this . _ scriptForPubkeys ( out ) ;
else
else
@ -201,8 +201,7 @@ TransactionBuilder.prototype._setInputMap = function() {
' Type:' + scriptPubKey . getRawOutType ( ) ) ;
' Type:' + scriptPubKey . getRawOutType ( ) ) ;
inputMap . push ( {
inputMap . push ( {
address : utxo . address , //TODO que pasa en multisig normal?
address : utxo . address ,
scriptPubKeyHex : utxo . scriptPubKey ,
scriptPubKey : scriptPubKey ,
scriptPubKey : scriptPubKey ,
scriptType : scriptType ,
scriptType : scriptType ,
i : i ,
i : i ,
@ -394,7 +393,6 @@ TransactionBuilder.prototype.setOutputs = function(outs) {
} ;
} ;
TransactionBuilder . _ mapKeys = function ( keys ) {
TransactionBuilder . _ mapKeys = function ( keys ) {
//prepare keys
//prepare keys
var walletKeyMap = { } ;
var walletKeyMap = { } ;
var l = keys . length ;
var l = keys . length ;
@ -437,10 +435,43 @@ TransactionBuilder.prototype._checkTx = function() {
throw new Error ( 'tx is not defined' ) ;
throw new Error ( 'tx is not defined' ) ;
} ;
} ;
TransactionBuilder . prototype . _ multiFindKey = function ( walletKeyMap , pubKeyHash ) {
var wk ;
[ networks . livenet , networks . testnet ] . forEach ( function ( n ) {
[ n . addressPubkey , n . addressScript ] . forEach ( function ( v ) {
var a = new Address ( v , pubKeyHash ) ;
if ( ! wk && walletKeyMap [ a ] ) {
wk = walletKeyMap [ a ] ;
}
} ) ;
} ) ;
return wk ;
} ;
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 ) {
var pubKeyHash = util . sha256ripe160 ( input . pubKeyBuf ) ;
wk = this . _ multiFindKey ( walletKeyMap , pubKeyHash ) ;
} else {
throw new Error ( 'no infomation at input to find keys' ) ;
}
return wk ;
} ;
TransactionBuilder . prototype . _ signPubKey = function ( walletKeyMap , input , txSigHash ) {
TransactionBuilder . prototype . _ signPubKey = function ( walletKeyMap , input , txSigHash ) {
if ( this . tx . ins [ input . i ] . s . length > 0 ) return { } ;
if ( this . tx . ins [ input . i ] . s . length > 0 ) return { } ;
var wk = walletKeyMap [ input . address ] ;
var wk = this . _ findWalletKey ( walletKeyMap , input ) ;
if ( ! wk ) return ;
if ( ! wk ) return ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
@ -451,14 +482,14 @@ TransactionBuilder.prototype._signPubKey = function(walletKeyMap, input, txSigHa
var scriptSig = new Script ( ) ;
var scriptSig = new Script ( ) ;
scriptSig . chunks . push ( sig ) ;
scriptSig . chunks . push ( sig ) ;
scriptSig . updateBuffer ( ) ;
scriptSig . updateBuffer ( ) ;
return { isFullySigned : true , script : scriptSig . getBuffer ( ) } ;
return { isFullySigned : true , signaturesAdded : true , s cript : scriptSig . getBuffer ( ) } ;
} ;
} ;
TransactionBuilder . prototype . _ signPubKeyHash = function ( walletKeyMap , input , txSigHash ) {
TransactionBuilder . prototype . _ signPubKeyHash = function ( walletKeyMap , input , txSigHash ) {
if ( this . tx . ins [ input . i ] . s . length > 0 ) return { } ;
if ( this . tx . ins [ input . i ] . s . length > 0 ) return { } ;
var wk = walletKeyMap [ input . address ] ;
var wk = this . _ findWalletKey ( walletKeyMap , input ) ;
if ( ! wk ) return ;
if ( ! wk ) return ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
var sigRaw = TransactionBuilder . _ signHashAndVerify ( wk , txSigHash ) ;
@ -470,18 +501,16 @@ TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txS
scriptSig . chunks . push ( sig ) ;
scriptSig . chunks . push ( sig ) ;
scriptSig . chunks . push ( wk . privKey . public ) ;
scriptSig . chunks . push ( wk . privKey . public ) ;
scriptSig . updateBuffer ( ) ;
scriptSig . updateBuffer ( ) ;
return { isFullySigned : true , script : scriptSig . getBuffer ( ) } ;
return { isFullySigned : true , signaturesAdded : true , s cript : scriptSig . getBuffer ( ) } ;
} ;
} ;
// FOR TESTING
// FOR TESTING
/ *
// var _dumpChunks = function (scriptSig, label) {
var _ dumpChunks = function ( scriptSig , label ) {
// console.log('## DUMP: ' + label + ' ##');
console . log ( '## DUMP: ' + label + ' ##' ) ;
// for(var i=0; i<scriptSig.chunks.length; i++) {
for ( var i = 0 ; i < scriptSig . chunks . length ; i ++ ) {
// console.log('\tCHUNK ', i, scriptSig.chunks[i]);
console . log ( '\tCHUNK ' , i , scriptSig . chunks [ i ] ) ;
// }
}
// };
} ;
* /
TransactionBuilder . prototype . _ initMultiSig = function ( scriptSig , nreq ) {
TransactionBuilder . prototype . _ initMultiSig = function ( scriptSig , nreq ) {
var wasUpdated = false ;
var wasUpdated = false ;
@ -514,6 +543,7 @@ TransactionBuilder.prototype._chunkIsEmpty = function(chunk) {
buffertools . compare ( chunk , util . EMPTY_BUFFER ) === 0 ;
buffertools . compare ( chunk , util . EMPTY_BUFFER ) === 0 ;
} ;
} ;
TransactionBuilder . prototype . _ updateMultiSig = function ( wk , scriptSig , txSigHash , nreq ) {
TransactionBuilder . prototype . _ updateMultiSig = function ( wk , scriptSig , txSigHash , nreq ) {
var wasUpdated = this . _ initMultiSig ( scriptSig , nreq ) ;
var wasUpdated = this . _ initMultiSig ( scriptSig , nreq ) ;
@ -540,40 +570,6 @@ TransactionBuilder.prototype._updateMultiSig = function(wk, scriptSig, txSigHash
} ;
} ;
TransactionBuilder . prototype . _ multiFindKey = function ( walletKeyMap , pubKeyHash ) {
var wk ;
[ networks . livenet , networks . testnet ] . forEach ( function ( n ) {
[ n . addressPubkey , n . addressScript ] . forEach ( function ( v ) {
var a = new Address ( v , pubKeyHash ) ;
if ( ! wk && walletKeyMap [ a ] ) {
wk = walletKeyMap [ a ] ;
}
} ) ;
} ) ;
return wk ;
} ;
TransactionBuilder . prototype . _ countMultiSig = function ( script ) {
var nsigs = 0 ;
for ( var i = 1 ; i < script . chunks . length ; i ++ )
if ( ! this . _ chunkIsEmpty ( script . chunks [ i ] ) )
nsigs ++ ;
return nsigs ;
} ;
TransactionBuilder . prototype . countInputMultiSig = function ( i ) {
var s = new Script ( this . tx . ins [ i ] . s ) ;
if ( ! s . chunks . length || s . chunks [ 0 ] !== 0 )
return 0 ; // does not seems multisig
return this . _ countMultiSig ( s ) ;
} ;
TransactionBuilder . prototype . _ signMultiSig = function ( walletKeyMap , input , txSigHash ) {
TransactionBuilder . prototype . _ signMultiSig = function ( walletKeyMap , input , txSigHash ) {
var pubkeys = input . scriptPubKey . capture ( ) ,
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
@ -581,76 +577,96 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
originalScriptBuf = this . tx . ins [ input . i ] . s ;
originalScriptBuf = this . tx . ins [ input . i ] . s ;
var scriptSig = new Script ( originalScriptBuf ) ;
var scriptSig = new Script ( originalScriptBuf ) ;
var signaturesAdded = false ;
for ( var j = 0 ; j < l && this . _ countMultiSig ( scriptSig ) < nreq ; j ++ ) {
for ( var j = 0 ; j < l && scriptSig . countMissingSignatures ( ) ; j ++ ) {
var wk = this . _ findWalletKey ( walletKeyMap , { pubKeyBuf : pubkeys [ j ] } ) ;
var pubKeyHash = util . sha256ripe160 ( pubkeys [ j ] ) ;
var wk = this . _ multiFindKey ( walletKeyMap , pubKeyHash ) ;
if ( ! wk ) continue ;
if ( ! wk ) continue ;
var newScriptSig = this . _ updateMultiSig ( wk , scriptSig , txSigHash , nreq ) ;
var newScriptSig = this . _ updateMultiSig ( wk , scriptSig , txSigHash , nreq ) ;
if ( newScriptSig )
if ( newScriptSig ) {
scriptSig = newScriptSig ;
scriptSig = newScriptSig ;
signaturesAdded = true ;
}
}
}
return {
return {
isFullySigned : this . _ countMultiSig ( scriptSig ) === nreq ,
isFullySigned : scriptSig . countMissingSignatures ( ) === 0 ,
signaturesAdded : signaturesAdded ,
script : scriptSig . getBuffer ( ) ,
script : scriptSig . getBuffer ( ) ,
} ;
} ;
} ;
} ;
var fnToSign = { } ;
var fnToSign = { } ;
TransactionBuilder . prototype . _ scriptIsAppended = function ( script , scriptToAddBuf ) {
var len = script . chunks . length ;
TransactionBuilder . prototype . _ signScriptHash = function ( walletKeyMap , input , txSigHash ) {
if ( script . chunks [ len - 1 ] === undefined )
var originalScriptBuf = this . tx . ins [ input . i ] . s ;
return false ;
if ( typeof script . chunks [ len - 1 ] === 'number' )
return false ;
if ( buffertools . compare ( script . chunks [ len - 1 ] , scriptToAddBuf ) !== 0 )
return false ;
return true ;
} ;
if ( ! this . hashToScriptMap )
TransactionBuilder . prototype . _ addScript = function ( scriptBuf , scriptToAddBuf ) {
throw new Error ( 'hashToScriptMap not set' ) ;
var s = new Script ( scriptBuf ) ;
var scriptHex = this . hashToScriptMap [ input . address ] ;
if ( ! this . _ scriptIsAppended ( s , scriptToAddBuf ) ) {
if ( ! scriptHex ) return ;
s . chunks . push ( scriptToAddBuf ) ;
s . updateBuffer ( ) ;
}
return s . getBuffer ( ) ;
} ;
var script = new Script ( new Buffer ( scriptHex , 'hex' ) ) ;
TransactionBuilder . prototype . _ getInputForP2sh = function ( script , index ) {
var scriptType = script . classify ( ) ;
var scriptType = script . classify ( ) ;
var scriptPubKeyHex = script . getBuffer ( ) . toString ( 'hex' ) ;
// pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys.
var pubKeyHash ;
if ( ! fnToSign [ scriptType ] )
switch ( scriptType ) {
throw new Error ( 'dont know how to sign p2sh script type' + script . getRawOutType ( ) ) ;
case Script . TX_PUBKEYHASH :
pubKeyHash = script . captureOne ( ) ;
break ;
case Script . TX_PUBKEY :
var chunk = script . captureOne ( ) ;
pubKeyHash = util . sha256ripe160 ( chunk ) ;
}
var newInput = {
return {
address : 'TODO' , // if p2pkubkeyhash -> get the address
i : index ,
i : input . i ,
pubKeyHash : pubKeyHash ,
scriptPubKey : script ,
scriptPubKey : script ,
scriptPubKeyHex : scriptPubKeyHex ,
scriptType : scriptType ,
scriptType : scriptType ,
} ;
} ;
} ;
var txSigHash2 = this . tx . hashForSignature ( script , input . i , this . signhash ) ;
var ret = fnToSign [ scriptType ] . call ( this , walletKeyMap , newInput , txSigHash2 ) ;
var rc = 1 ; //TODO : si alguno firmó...
TransactionBuilder . prototype . _ signScriptHash = function ( walletKeyMap , input , txSigHash ) {
if ( ret . script ) {
var originalScriptBuf = this . tx . ins [ input . i ] . s ;
console . log ( '[TransactionBuilder.js.634] IN' ) ; //TODO
if ( ! this . hashToScriptMap )
var scriptSig = new Script ( originalScriptBuf ) ;
throw new Error ( 'hashToScriptMap not set' ) ;
var len = scriptSig . chunks . length ;
var scriptBufNotAlreadyAppended = scriptSig . chunks [ len - 1 ] !== undefined && ( typeof scriptSig . chunks [ len - 1 ] == "number" || scriptSig . chunks [ len - 1 ] . toString ( 'hex' ) != scriptBuf . toString ( 'hex' ) ) ;
if ( rc > 0 && scriptBufNotAlreadyAppended ) {
scriptSig . chunks . push ( scriptBuf ) ;
scriptSig . updateBuffer ( ) ;
ret . script = scriptSig . getBuffer ( ) ;
}
if ( scriptType == Script . TX_MULTISIG && scriptSig . finishedMultiSig ( ) )
var scriptHex = this . hashToScriptMap [ input . address ] ;
{
if ( ! scriptHex ) return ;
scriptSig . removePlaceHolders ( ) ;
scriptSig . prependOp0 ( ) ;
var scriptBuf = new Buffer ( scriptHex , 'hex' ) ;
ret . script = scriptSig . getBuffer ( ) ;
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 ( ) ) ;
var newInput = this . _ getInputForP2sh ( script , input . i ) ;
var newTxSigHash = this . tx . hashForSignature ( script , newInput . i , this . signhash ) ;
var ret = fnToSign [ scriptType ] . call ( this , walletKeyMap , newInput , newTxSigHash ) ;
if ( ret && ret . script && ret . signaturesAdded ) {
ret . script = this . _ addScript ( ret . script , scriptBuf ) ;
}
return ret ;
return ret ;
} ;
} ;
@ -676,17 +692,16 @@ TransactionBuilder.prototype.sign = function(keys) {
var ret = fnToSign [ input . scriptType ] . call ( this , walletKeyMap , input , txSigHash ) ;
var ret = fnToSign [ input . scriptType ] . call ( this , walletKeyMap , input , txSigHash ) ;
if ( ret && ret . script ) {
if ( ret && ret . script ) {
tx . ins [ i ] . s = ret . script ; //esto no aqui TODO
tx . ins [ i ] . s = ret . script ;
if ( ret . isFullySigned ) this . inputsSigned ++ ;
if ( ret . isFullySigned ) this . inputsSigned ++ ;
}
}
}
}
return this ;
return this ;
} ;
} ;
// [addr -> script ]
// [ { address:scriptHex } ]
TransactionBuilder . prototype . setHashToScriptMap = function ( hashToScriptMap ) {
TransactionBuilder . prototype . setHashToScriptMap = function ( hashToScriptMap ) {
this . hashToScriptMap = hashToScriptMap ;
this . hashToScriptMap = hashToScriptMap ;
return this ;
return this ;
} ;
} ;