Merge pull request #196 from matiu/feature/remove-unused-code
remove blockchain* inputcache* related code
This commit is contained in:
commit
4ceacec9e8
270
Transaction.js
270
Transaction.js
|
@ -211,148 +211,6 @@ Transaction.prototype.inputs = function inputs() {
|
|||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load and cache transaction inputs.
|
||||
*
|
||||
* This function will try to load the inputs for a transaction.
|
||||
*
|
||||
* @param {BlockChain} blockChain A reference to the BlockChain object.
|
||||
* @param {TransactionMap|null} txStore Additional transactions to consider.
|
||||
* @param {Boolean} wait Whether to keep trying until the dependencies are
|
||||
* met (or a timeout occurs.)
|
||||
* @param {Function} callback Function to call on completion.
|
||||
*/
|
||||
Transaction.prototype.cacheInputs =
|
||||
function cacheInputs(blockChain, txStore, wait, callback) {
|
||||
var self = this;
|
||||
|
||||
var txCache = new TransactionInputsCache(this);
|
||||
txCache.buffer(blockChain, txStore, wait, callback);
|
||||
};
|
||||
|
||||
Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
|
||||
var self = this;
|
||||
|
||||
var txIndex = txCache.txIndex;
|
||||
|
||||
var outpoints = [];
|
||||
|
||||
var valueIn = bignum(0);
|
||||
var valueOut = bignum(0);
|
||||
|
||||
function getTxOut(txin, n) {
|
||||
var outHash = txin.getOutpointHash();
|
||||
var outIndex = txin.getOutpointIndex();
|
||||
var outHashBase64 = outHash.toString('base64');
|
||||
var fromTxOuts = txIndex[outHashBase64];
|
||||
|
||||
if (!fromTxOuts) {
|
||||
throw new MissingSourceError(
|
||||
"Source tx " + util.formatHash(outHash) +
|
||||
" for inputs " + n + " not found",
|
||||
// We store the hash of the missing tx in the error
|
||||
// so that the txStore can watch out for it.
|
||||
outHash.toString('base64')
|
||||
);
|
||||
}
|
||||
|
||||
var txout = fromTxOuts[outIndex];
|
||||
|
||||
if (!txout) {
|
||||
throw new Error("Source output index " + outIndex +
|
||||
" for input " + n + " out of bounds");
|
||||
}
|
||||
|
||||
return txout;
|
||||
}
|
||||
|
||||
Step(
|
||||
function verifyInputs(opts) {
|
||||
var group = this.group();
|
||||
|
||||
if (self.isCoinBase()) {
|
||||
throw new Error("Coinbase tx are invalid unless part of a block");
|
||||
}
|
||||
|
||||
self.ins.forEach(function(txin, n) {
|
||||
var txout = getTxOut(txin, n);
|
||||
|
||||
// TODO: Verify coinbase maturity
|
||||
|
||||
valueIn = valueIn.add(util.valueToBigInt(txout.v));
|
||||
|
||||
outpoints.push(txin.o);
|
||||
|
||||
self.verifyInput(n, txout.getScript(), opts, group());
|
||||
});
|
||||
},
|
||||
|
||||
function verifyInputsResults(err, results) {
|
||||
if (err) throw err;
|
||||
|
||||
for (var i = 0, l = results.length; i < l; i++) {
|
||||
if (!results[i]) {
|
||||
var txout = getTxOut(self.ins[i]);
|
||||
log.debug('Script evaluated to false');
|
||||
log.debug('|- scriptSig', "" + self.ins[i].getScript());
|
||||
log.debug('`- scriptPubKey', "" + txout.getScript());
|
||||
throw new VerificationError('Script for input ' + i + ' evaluated to false');
|
||||
}
|
||||
}
|
||||
|
||||
this();
|
||||
},
|
||||
|
||||
function queryConflicts(err) {
|
||||
if (err) throw err;
|
||||
|
||||
// Make sure there are no other transactions spending the same outs
|
||||
blockChain.countConflictingTransactions(outpoints, this);
|
||||
},
|
||||
function checkConflicts(err, count) {
|
||||
if (err) throw err;
|
||||
|
||||
self.outs.forEach(function(txout) {
|
||||
valueOut = valueOut.add(util.valueToBigInt(txout.v));
|
||||
});
|
||||
|
||||
if (valueIn.cmp(valueOut) < 0) {
|
||||
var outValue = util.formatValue(valueOut);
|
||||
var inValue = util.formatValue(valueIn);
|
||||
throw new Error("Tx output value (BTC " + outValue + ") " +
|
||||
"exceeds input value (BTC " + inValue + ")");
|
||||
}
|
||||
|
||||
var fees = valueIn.sub(valueOut);
|
||||
|
||||
if (count) {
|
||||
// Spent output detected, retrieve transaction that spends it
|
||||
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()));
|
||||
// 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())));
|
||||
}
|
||||
} else {
|
||||
callback(new Error("Outputs of this transaction are spent, but " +
|
||||
"the transaction(s) that spend them are not " +
|
||||
"available. This probably means you need to " +
|
||||
"reset your database."));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Success
|
||||
this(null, fees);
|
||||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, opts, callback) {
|
||||
var scriptSig = this.ins[n].getScript();
|
||||
return ScriptInterpreter.verifyFull(
|
||||
|
@ -1110,132 +968,4 @@ Transaction.createAndSign = function(utxos, outs, keys, opts) {
|
|||
return ret;
|
||||
};
|
||||
|
||||
var TransactionInputsCache = exports.TransactionInputsCache =
|
||||
function TransactionInputsCache(tx) {
|
||||
var txList = [];
|
||||
var txList64 = [];
|
||||
var reqOuts = {};
|
||||
|
||||
// Get list of transactions required for verification
|
||||
tx.ins.forEach(function(txin) {
|
||||
if (txin.isCoinBase()) return;
|
||||
|
||||
var hash = txin.o.slice(0, 32);
|
||||
var hash64 = hash.toString('base64');
|
||||
if (txList64.indexOf(hash64) == -1) {
|
||||
txList.push(hash);
|
||||
txList64.push(hash64);
|
||||
}
|
||||
if (!reqOuts[hash64]) {
|
||||
reqOuts[hash64] = [];
|
||||
}
|
||||
reqOuts[hash64][txin.getOutpointIndex()] = true;
|
||||
});
|
||||
|
||||
this.tx = tx;
|
||||
this.txList = txList;
|
||||
this.txList64 = txList64;
|
||||
this.txIndex = {};
|
||||
this.requiredOuts = reqOuts;
|
||||
this.callbacks = [];
|
||||
};
|
||||
|
||||
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback) {
|
||||
var self = this;
|
||||
|
||||
var complete = false;
|
||||
|
||||
if ("function" === typeof callback) {
|
||||
self.callbacks.push(callback);
|
||||
}
|
||||
|
||||
var missingTx = {};
|
||||
self.txList64.forEach(function(hash64) {
|
||||
missingTx[hash64] = true;
|
||||
});
|
||||
|
||||
// A utility function to create the index object from the txs result lists
|
||||
function indexTxs(err, txs) {
|
||||
if (err) throw err;
|
||||
|
||||
// Index memory transactions
|
||||
txs.forEach(function(tx) {
|
||||
var hash64 = tx.getHash().toString('base64');
|
||||
var obj = {};
|
||||
Object.keys(self.requiredOuts[hash64]).forEach(function(o) {
|
||||
obj[+o] = tx.outs[+o];
|
||||
});
|
||||
self.txIndex[hash64] = obj;
|
||||
delete missingTx[hash64];
|
||||
});
|
||||
|
||||
this(null);
|
||||
};
|
||||
|
||||
Step(
|
||||
// First find and index memory transactions (if a txStore was provided)
|
||||
function findMemTx() {
|
||||
if (txStore) {
|
||||
txStore.find(self.txList64, this);
|
||||
} else {
|
||||
this(null, []);
|
||||
}
|
||||
},
|
||||
indexTxs,
|
||||
// Second find and index persistent transactions
|
||||
function findBlockChainTx(err) {
|
||||
if (err) throw err;
|
||||
|
||||
// TODO: Major speedup should be possible if we load only the outs and not
|
||||
// whole transactions.
|
||||
var callback = this;
|
||||
blockChain.getOutputsByHashes(self.txList, function(err, result) {
|
||||
callback(err, result);
|
||||
});
|
||||
},
|
||||
indexTxs,
|
||||
function saveTxCache(err) {
|
||||
if (err) throw err;
|
||||
|
||||
var missingTxDbg = '';
|
||||
if (Object.keys(missingTx).length) {
|
||||
missingTxDbg = Object.keys(missingTx).map(function(hash64) {
|
||||
return util.formatHash(new Buffer(hash64, 'base64'));
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
if (wait && Object.keys(missingTx).length) {
|
||||
// TODO: This might no longer be needed now that saveTransactions uses
|
||||
// the safe=true option.
|
||||
setTimeout(function() {
|
||||
var missingHashes = Object.keys(missingTx);
|
||||
if (missingHashes.length) {
|
||||
self.callback(new Error('Missing inputs (timeout while searching): ' + missingTxDbg));
|
||||
} else if (!complete) {
|
||||
self.callback(new Error('Callback failed to trigger'));
|
||||
}
|
||||
}, 10000);
|
||||
} else {
|
||||
complete = true;
|
||||
this(null, self);
|
||||
}
|
||||
},
|
||||
self.callback.bind(self)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
TransactionInputsCache.prototype.callback = function callback(err) {
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
|
||||
// Empty the callback array first (because downstream functions could add new
|
||||
// callbacks or otherwise interfere if were not in a consistent state.)
|
||||
var cbs = this.callbacks;
|
||||
this.callbacks = [];
|
||||
|
||||
cbs.forEach(function(cb) {
|
||||
cb.apply(null, args);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = require('soop')(Transaction);
|
||||
|
|
Loading…
Reference in New Issue