|
|
@ -204,7 +204,7 @@ Transaction.prototype.inputs = function inputs() { |
|
|
|
} |
|
|
|
|
|
|
|
return res; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Load and cache transaction inputs. |
|
|
@ -325,14 +325,11 @@ Transaction.prototype.verify = function verify(txCache, blockChain, callback) { |
|
|
|
blockChain.getConflictingTransactions(outpoints, function(err, results) { |
|
|
|
if (results.length) { |
|
|
|
if (buffertools.compare(results[0].getHash(), self.getHash()) === 0) { |
|
|
|
log.warn("Detected tx re-add (recoverable db corruption): " |
|
|
|
+ util.formatHashAlt(results[0].getHash())); |
|
|
|
log.warn("Detected tx re-add (recoverable db corruption): " + util.formatHashAlt(results[0].getHash())); |
|
|
|
// TODO: Needs to return an error for the memory pool case?
|
|
|
|
callback(null, fees); |
|
|
|
} else { |
|
|
|
callback(new Error("At least one referenced output has" |
|
|
|
+ " already been spent in tx " |
|
|
|
+ util.formatHashAlt(results[0].getHash()))); |
|
|
|
callback(new Error("At least one referenced output has" + " already been spent in tx " + util.formatHashAlt(results[0].getHash()))); |
|
|
|
} |
|
|
|
} else { |
|
|
|
callback(new Error("Outputs of this transaction are spent, but " + |
|
|
@ -352,13 +349,13 @@ Transaction.prototype.verify = function verify(txCache, blockChain, callback) { |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, opts, callback) { |
|
|
|
var valid = ScriptInterpreter.verifyFull( |
|
|
|
this.ins[n].getScript(), |
|
|
|
var scriptSig = this.ins[n].getScript(); |
|
|
|
return ScriptInterpreter.verifyFull( |
|
|
|
scriptSig, |
|
|
|
scriptPubKey, |
|
|
|
this, n, 0, |
|
|
|
opts, |
|
|
|
callback); |
|
|
|
return valid; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
@ -375,7 +372,6 @@ Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) { |
|
|
|
|
|
|
|
// Index any pubkeys affected by the outputs of this transaction
|
|
|
|
for (var i = 0, l = this.outs.length; i < l; i++) { |
|
|
|
try { |
|
|
|
var txout = this.outs[i]; |
|
|
|
var script = txout.getScript(); |
|
|
|
|
|
|
@ -383,18 +379,11 @@ Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) { |
|
|
|
if (outPubKey) { |
|
|
|
this.affects.push(outPubKey); |
|
|
|
} |
|
|
|
} catch (err) { |
|
|
|
// It's not our job to validate, so we just ignore any errors and issue
|
|
|
|
// a very low level log message.
|
|
|
|
log.debug("Unable to determine affected pubkeys: " + |
|
|
|
(err.stack ? err.stack : ""+err)); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// Index any pubkeys affected by the inputs of this transaction
|
|
|
|
var txIndex = txCache.txIndex; |
|
|
|
for (var i = 0, l = this.ins.length; i < l; i++) { |
|
|
|
try { |
|
|
|
var txin = this.ins[i]; |
|
|
|
|
|
|
|
if (txin.isCoinBase()) continue; |
|
|
@ -418,12 +407,6 @@ Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) { |
|
|
|
if (outPubKey) { |
|
|
|
this.affects.push(outPubKey); |
|
|
|
} |
|
|
|
} catch (err) { |
|
|
|
// It's not our job to validate, so we just ignore any errors and issue
|
|
|
|
// a very low level log message.
|
|
|
|
log.debug("Unable to determine affected pubkeys: " + |
|
|
|
(err.stack ? err.stack : ""+err)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -937,13 +920,15 @@ Transaction.prototype.sign = function (selectedUtxos, keys, opts) { |
|
|
|
|
|
|
|
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; |
|
|
@ -1026,8 +1011,7 @@ Transaction.create = function (utxos, outs, opts) { |
|
|
|
do { |
|
|
|
// based on https://en.bitcoin.it/wiki/Transaction_fees
|
|
|
|
maxSizeK = parseInt(size / 1000) + 1; |
|
|
|
var feeSat = givenFeeSat |
|
|
|
? givenFeeSat : maxSizeK * FEE_PER_1000B_SAT ; |
|
|
|
var feeSat = givenFeeSat ? givenFeeSat : maxSizeK * FEE_PER_1000B_SAT; |
|
|
|
|
|
|
|
var valueOutSat = Transaction |
|
|
|
._sumOutputs(outs) |
|
|
@ -1038,10 +1022,7 @@ Transaction.create = function (utxos, outs, opts) { |
|
|
|
|
|
|
|
if (!selectedUtxos) { |
|
|
|
throw new Error( |
|
|
|
'the given UTXOs dont sum up the given outputs: ' |
|
|
|
+ valueOutSat.toString() |
|
|
|
+ ' (fee is ' + feeSat |
|
|
|
+ ' )SAT' |
|
|
|
'the given UTXOs dont sum up the given outputs: ' + valueOutSat.toString() + ' (fee is ' + feeSat + ' )SAT' |
|
|
|
); |
|
|
|
} |
|
|
|
var tx = Transaction.createWithFee(selectedUtxos, outs, feeSat, { |
|
|
@ -1052,7 +1033,10 @@ Transaction.create = function (utxos, outs, opts) { |
|
|
|
size = tx.getSize(); |
|
|
|
} while (size > (maxSizeK + 1) * 1000); |
|
|
|
|
|
|
|
return {tx: tx, selectedUtxos: selectedUtxos}; |
|
|
|
return { |
|
|
|
tx: tx, |
|
|
|
selectedUtxos: selectedUtxos |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -1126,8 +1110,7 @@ Transaction.createAndSign = function (utxos, outs, keys, opts) { |
|
|
|
}; |
|
|
|
|
|
|
|
var TransactionInputsCache = exports.TransactionInputsCache = |
|
|
|
function TransactionInputsCache(tx) |
|
|
|
{ |
|
|
|
function TransactionInputsCache(tx) { |
|
|
|
var txList = []; |
|
|
|
var txList64 = []; |
|
|
|
var reqOuts = {}; |
|
|
@ -1156,8 +1139,7 @@ function TransactionInputsCache(tx) |
|
|
|
this.callbacks = []; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback) |
|
|
|
{ |
|
|
|
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var complete = false; |
|
|
@ -1227,8 +1209,7 @@ TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, w |
|
|
|
setTimeout(function() { |
|
|
|
var missingHashes = Object.keys(missingTx); |
|
|
|
if (missingHashes.length) { |
|
|
|
self.callback(new Error('Missing inputs (timeout while searching): ' |
|
|
|
+ missingTxDbg)); |
|
|
|
self.callback(new Error('Missing inputs (timeout while searching): ' + missingTxDbg)); |
|
|
|
} else if (!complete) { |
|
|
|
self.callback(new Error('Callback failed to trigger')); |
|
|
|
} |
|
|
@ -1243,8 +1224,7 @@ TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, w |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
TransactionInputsCache.prototype.callback = function callback(err) |
|
|
|
{ |
|
|
|
TransactionInputsCache.prototype.callback = function callback(err) { |
|
|
|
var args = Array.prototype.slice.apply(arguments); |
|
|
|
|
|
|
|
// Empty the callback array first (because downstream functions could add new
|
|
|
@ -1252,14 +1232,9 @@ TransactionInputsCache.prototype.callback = function callback(err) |
|
|
|
var cbs = this.callbacks; |
|
|
|
this.callbacks = []; |
|
|
|
|
|
|
|
try { |
|
|
|
cbs.forEach(function(cb) { |
|
|
|
cb.apply(null, args); |
|
|
|
}); |
|
|
|
} catch (err) { |
|
|
|
log.err("Callback error after connecting tx inputs: "+ |
|
|
|
(err.stack ? err.stack : err.toString())); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
module.exports = require('soop')(Transaction); |
|
|
|