Merge pull request #196 from matiu/feature/remove-unused-code

remove blockchain* inputcache* related code
This commit is contained in:
Ryan X. Charles 2014-03-27 11:59:43 -04:00
commit 4ceacec9e8
1 changed files with 0 additions and 270 deletions

View File

@ -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);