@ -1243,6 +1243,9 @@ WalletService.prototype._checkTxAndEstimateFee = function(txp) {
txp . estimateFee ( ) ;
txp . estimateFee ( ) ;
if ( txp . getEstimatedSize ( ) / 1000 > Defaults . MAX_TX_SIZE_IN_KB )
return Errors . TX_MAX_SIZE_EXCEEDED ;
try {
try {
var bitcoreTx = txp . getBitcoreTx ( ) ;
var bitcoreTx = txp . getBitcoreTx ( ) ;
bitcoreError = bitcoreTx . getSerializationError ( serializationOpts ) ;
bitcoreError = bitcoreTx . getSerializationError ( serializationOpts ) ;
@ -1337,8 +1340,6 @@ WalletService.prototype._selectTxInputs = function(txp, utxosToExclude, cb) {
txp . setInputs ( selected ) ;
txp . setInputs ( selected ) ;
bitcoreError = self . _ checkTxAndEstimateFee ( txp ) ;
bitcoreError = self . _ checkTxAndEstimateFee ( txp ) ;
if ( ! bitcoreError ) return cb ( ) ;
if ( ! bitcoreError ) return cb ( ) ;
if ( txp . getEstimatedSize ( ) / 1000 > Defaults . MAX_TX_SIZE_IN_KB )
return cb ( Errors . TX_MAX_SIZE_EXCEEDED ) ;
}
}
setTimeout ( select , 0 ) ;
setTimeout ( select , 0 ) ;
} ;
} ;
@ -1404,10 +1405,15 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
var sizePerInput = txp . getEstimatedSizeForSingleInput ( ) ;
var sizePerInput = txp . getEstimatedSizeForSingleInput ( ) ;
var feePerInput = sizePerInput * txp . feePerKb / 1000. ;
var feePerInput = sizePerInput * txp . feePerKb / 1000. ;
var totalValueInUtxos = _ . sum ( utxos , 'satoshis' ) - baseTxpFee - ( utxos . length * feePerInput ) ;
var totalValueInUtxos = _ . sum ( utxos , 'satoshis' ) ;
var netValueInUtxos = totalValueInUtxos - baseTxpFee - ( utxos . length * feePerInput ) ;
if ( totalValueInUtxos < txpAmount ) {
if ( totalValueInUtxos < txpAmount ) {
log . debug ( 'Value in all utxos (' + formatAmount ( totalValueInUtxos ) + ') is inusufficient to cover for txp amount (' + formatAmount ( txpAmount ) + ')' ) ; // TODO
log . debug ( 'Total value in all utxos (' + formatAmount ( totalValueInUtxos ) + ') is insufficient to cover for txp amount (' + formatAmount ( txpAmount ) + ')' ) ; // TODO
return false ;
return Errors . INSUFFICIENT_FUNDS ;
}
if ( netValueInUtxos < txpAmount ) {
log . debug ( 'Value after fees in all utxos (' + formatAmount ( netValueInUtxos ) + ') is insufficient to cover for txp amount (' + formatAmount ( txpAmount ) + ')' ) ; // TODO
return Errors . INSUFFICIENT_FUNDS_FOR_FEE ;
}
}
var bigInputThreshold = txpAmount * Defaults . UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR + ( baseTxpFee + feePerInput ) ;
var bigInputThreshold = txpAmount * Defaults . UTXO_SELECTION_MAX_SINGLE_UTXO_FACTOR + ( baseTxpFee + feePerInput ) ;
@ -1427,6 +1433,7 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
var total = 0 ;
var total = 0 ;
var selected = [ ] ;
var selected = [ ] ;
var error ;
_ . each ( smallInputs , function ( input , i ) {
_ . each ( smallInputs , function ( input , i ) {
log . debug ( 'Input #' + i + ': ' + formatInputs ( input ) ) ;
log . debug ( 'Input #' + i + ': ' + formatInputs ( input ) ) ;
@ -1444,6 +1451,8 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
var txpSize = baseTxpSize + selected . length * sizePerInput ;
var txpSize = baseTxpSize + selected . length * sizePerInput ;
var txpFee = baseTxpFee + selected . length * feePerInput ;
var txpFee = baseTxpFee + selected . length * feePerInput ;
log . debug ( 'Tx size: ' + formatSize ( txpSize ) + ', Tx fee: ' + formatAmount ( txpFee ) ) ;
var amountVsFeeRatio = txpFee / txpAmount ;
var amountVsFeeRatio = txpFee / txpAmount ;
var singleInputFeeVsFeeRatio = txpFee / ( baseTxpFee + feePerInput ) ;
var singleInputFeeVsFeeRatio = txpFee / ( baseTxpFee + feePerInput ) ;
var amountVsUtxoRatio = inputAmount / txpAmount ;
var amountVsUtxoRatio = inputAmount / txpAmount ;
@ -1452,6 +1461,12 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
log . debug ( 'Single-input fee/Multi-input fee: ' + formatRatio ( singleInputFeeVsFeeRatio ) + ' (max: ' + formatRatio ( Defaults . UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR ) + ')' + ' loses wrt single-input tx: ' + formatAmount ( ( selected . length - 1 ) * feePerInput ) ) ;
log . debug ( 'Single-input fee/Multi-input fee: ' + formatRatio ( singleInputFeeVsFeeRatio ) + ' (max: ' + formatRatio ( Defaults . UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR ) + ')' + ' loses wrt single-input tx: ' + formatAmount ( ( selected . length - 1 ) * feePerInput ) ) ;
log . debug ( 'Tx amount/input amount:' + formatRatio ( amountVsUtxoRatio ) + ' (min: ' + formatRatio ( Defaults . UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR ) + ')' ) ;
log . debug ( 'Tx amount/input amount:' + formatRatio ( amountVsUtxoRatio ) + ' (min: ' + formatRatio ( Defaults . UTXO_SELECTION_MIN_TX_AMOUNT_VS_UTXO_FACTOR ) + ')' ) ;
if ( txpSize / 1000. > Defaults . MAX_TX_SIZE_IN_KB ) {
log . debug ( 'Breaking because tx size (' + formatSize ( txpSize ) + ') is too big (max: ' + formatSize ( Defaults . MAX_TX_SIZE_IN_KB * 1000. ) + ')' ) ; // TODO
error = Errors . TX_MAX_SIZE_EXCEEDED ;
return false ;
}
if ( ! _ . isEmpty ( bigInputs ) ) {
if ( ! _ . isEmpty ( bigInputs ) ) {
if ( ( amountVsFeeRatio > Defaults . UTXO_SELECTION_MAX_TX_AMOUNT_VS_FEE_FACTOR &&
if ( ( amountVsFeeRatio > Defaults . UTXO_SELECTION_MAX_TX_AMOUNT_VS_FEE_FACTOR &&
singleInputFeeVsFeeRatio > Defaults . UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR ) ) {
singleInputFeeVsFeeRatio > Defaults . UTXO_SELECTION_MAX_FEE_VS_SINGLE_UTXO_FEE_FACTOR ) ) {
@ -1463,12 +1478,6 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
log . debug ( 'Breaking because utxo is too small compared to tx amount' ) ;
log . debug ( 'Breaking because utxo is too small compared to tx amount' ) ;
return false ;
return false ;
}
}
if ( txpSize / 1000. > Defaults . MAX_TX_SIZE_IN_KB ) {
log . debug ( 'Breaking because tx size is too big (' + formatSize ( txpSize ) + ')' ) ; // TODO
return false ;
}
}
}
total += inputAmount ;
total += inputAmount ;
@ -1489,11 +1498,9 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
}
}
}
}
if ( ! _ . isEmpty ( selected ) ) {
if ( _ . isEmpty ( selected ) ) {
var lockedOverhead = total - txpAmount ;
log . debug ( 'Could not find enough funds within this utxo subset' ) ;
log . debug ( 'SUCCESS! Total locked: ' + formatAmount ( total ) + ', overhead: ' + formatAmount ( lockedOverhead ) + ' (' + formatRatio ( lockedOverhead / txpAmount ) + ')' ) ;
return error || Errors . INSUFFICIENT_FUNDS_FOR_FEE ;
} else {
log . debug ( 'Could not find enough funds within this utxso subset' ) ;
}
}
return selected ;
return selected ;
@ -1531,6 +1538,7 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
var inputs = [ ] ;
var inputs = [ ] ;
var groups = [ 6 , 1 , 0 ] ;
var groups = [ 6 , 1 , 0 ] ;
var error ;
var lastGroupLength ;
var lastGroupLength ;
_ . each ( groups , function ( group ) {
_ . each ( groups , function ( group ) {
var candidateUtxos = _ . filter ( utxos , function ( utxo ) {
var candidateUtxos = _ . filter ( utxos , function ( utxo ) {
@ -1549,20 +1557,25 @@ WalletService.prototype._selectTxInputs2 = function(txp, utxosToExclude, cb) {
lastGroupLength = candidateUtxos . length ;
lastGroupLength = candidateUtxos . length ;
inputs = select ( candidateUtxos ) ;
var result = select ( candidateUtxos ) ;
if ( result && ! _ . isArray ( result ) ) {
error = result ;
} else {
inputs = result ;
error = null ;
}
log . debug ( 'Selected inputs from this group: ' + formatInputs ( inputs ) ) ;
log . debug ( 'Selected inputs from this group: ' + formatInputs ( inputs ) ) ;
if ( ! _ . isEmpty ( inputs ) ) return false ;
if ( ! _ . isEmpty ( inputs ) ) return false ;
} ) ;
} ) ;
if ( _ . isEmpty ( inputs ) ) return cb ( Errors . INSUFFICIENT_FUNDS_FOR_FEE ) ;
if ( error ) return cb ( error ) ;
txp . setInputs ( inputs ) ;
txp . setInputs ( inputs ) ;
if ( txp . getEstimatedSize ( ) / 1000 > Defaults . MAX_TX_SIZE_IN_KB )
return cb ( Errors . TX_MAX_SIZE_EXCEEDED ) ;
var err = self . _ checkTxAndEstimateFee ( txp ) ;
var err = self . _ checkTxAndEstimateFee ( txp ) ;
if ( ! err ) {
if ( ! err ) {
log . debug ( 'Successfully built transaction. Total fees: ' , formatAmount ( txp . fee ) ) ;
log . debug ( 'Successfully built transaction. Total fees: ' , formatAmount ( txp . fee ) ) ;
} else {
} else {