|
|
@ -1,25 +1,23 @@ |
|
|
|
require('classtool'); |
|
|
|
|
|
|
|
function spec(b) { |
|
|
|
var config = b.config || require('./config'); |
|
|
|
var log = b.log || require('./util/log'); |
|
|
|
var Address = b.Address || require('./Address').class(); |
|
|
|
var Script = b.Script || require('./Script').class(); |
|
|
|
var ScriptInterpreter = b.ScriptInterpreter || require('./ScriptInterpreter').class(); |
|
|
|
var util = b.util || require('./util/util'); |
|
|
|
var bignum = b.bignum || require('bignum'); |
|
|
|
var Put = b.Put || require('bufferput'); |
|
|
|
var Parser = b.Parser || require('./util/BinaryParser').class(); |
|
|
|
var Step = b.Step || require('step'); |
|
|
|
var buffertools = b.buffertools || require('buffertools'); |
|
|
|
|
|
|
|
var error = b.error || require('./util/error'); |
|
|
|
var VerificationError = error.VerificationError; |
|
|
|
var MissingSourceError = error.MissingSourceError; |
|
|
|
|
|
|
|
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]); |
|
|
|
|
|
|
|
function TransactionIn(data) { |
|
|
|
var imports = require('soop').imports(); |
|
|
|
|
|
|
|
var config = imports.config || require('./config'); |
|
|
|
var log = imports.log || require('./util/log'); |
|
|
|
var Address = imports.Address || require('./Address'); |
|
|
|
var Script = imports.Script || require('./Script'); |
|
|
|
var ScriptInterpreter = imports.ScriptInterpreter || require('./ScriptInterpreter'); |
|
|
|
var util = imports.util || require('./util/util'); |
|
|
|
var bignum = imports.bignum || require('bignum'); |
|
|
|
var Put = imports.Put || require('bufferput'); |
|
|
|
var Parser = imports.Parser || require('./util/BinaryParser'); |
|
|
|
var Step = imports.Step || require('step'); |
|
|
|
var buffertools = imports.buffertools || require('buffertools'); |
|
|
|
var error = imports.error || require('./util/error'); |
|
|
|
var VerificationError = error.VerificationError; |
|
|
|
var MissingSourceError = error.MissingSourceError; |
|
|
|
|
|
|
|
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]); |
|
|
|
|
|
|
|
function TransactionIn(data) { |
|
|
|
if ("object" !== typeof data) { |
|
|
|
data = {}; |
|
|
|
} |
|
|
@ -29,69 +27,69 @@ function spec(b) { |
|
|
|
this.s = Buffer.isBuffer(data.s) ? data.s : |
|
|
|
Buffer.isBuffer(data.script) ? data.script : util.EMPTY_BUFFER; |
|
|
|
this.q = data.q ? data.q : data.sequence; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
TransactionIn.prototype.getScript = function getScript() { |
|
|
|
TransactionIn.prototype.getScript = function getScript() { |
|
|
|
return new Script(this.s); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionIn.prototype.isCoinBase = function isCoinBase() { |
|
|
|
TransactionIn.prototype.isCoinBase = function isCoinBase() { |
|
|
|
return buffertools.compare(this.o, COINBASE_OP) === 0; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionIn.prototype.serialize = function serialize() { |
|
|
|
TransactionIn.prototype.serialize = function serialize() { |
|
|
|
var slen = util.varIntBuf(this.s.length); |
|
|
|
var qbuf = new Buffer(4); |
|
|
|
qbuf.writeUInt32LE(this.q, 0); |
|
|
|
|
|
|
|
return Buffer.concat([this.o, slen, this.s, qbuf]); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionIn.prototype.getOutpointHash = function getOutpointHash() { |
|
|
|
TransactionIn.prototype.getOutpointHash = function getOutpointHash() { |
|
|
|
if ("undefined" !== typeof this.o.outHashCache) { |
|
|
|
return this.o.outHashCache; |
|
|
|
} |
|
|
|
|
|
|
|
return this.o.outHashCache = this.o.slice(0, 32); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() { |
|
|
|
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() { |
|
|
|
return (this.o[32] ) + |
|
|
|
(this.o[33] << 8) + |
|
|
|
(this.o[34] << 16) + |
|
|
|
(this.o[35] << 24); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) { |
|
|
|
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) { |
|
|
|
this.o[32] = n & 0xff; |
|
|
|
this.o[33] = n >> 8 & 0xff; |
|
|
|
this.o[34] = n >> 16 & 0xff; |
|
|
|
this.o[35] = n >> 24 & 0xff; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
function TransactionOut(data) { |
|
|
|
function TransactionOut(data) { |
|
|
|
if ("object" !== typeof data) { |
|
|
|
data = {}; |
|
|
|
} |
|
|
|
this.v = data.v ? data.v : data.value; |
|
|
|
this.s = data.s ? data.s : data.script; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionOut.prototype.getValue = function getValue() { |
|
|
|
TransactionOut.prototype.getValue = function getValue() { |
|
|
|
return new Parser(this.v).word64lu(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionOut.prototype.getScript = function getScript() { |
|
|
|
TransactionOut.prototype.getScript = function getScript() { |
|
|
|
return new Script(this.s); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
TransactionOut.prototype.serialize = function serialize() { |
|
|
|
TransactionOut.prototype.serialize = function serialize() { |
|
|
|
var slen = util.varIntBuf(this.s.length); |
|
|
|
return Buffer.concat([this.v, slen, this.s]); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
function Transaction(data) { |
|
|
|
function Transaction(data) { |
|
|
|
if ("object" !== typeof data) { |
|
|
|
data = {}; |
|
|
|
} |
|
|
@ -112,16 +110,16 @@ function spec(b) { |
|
|
|
return txout; |
|
|
|
}) : []; |
|
|
|
if (data.buffer) this._buffer = data.buffer; |
|
|
|
}; |
|
|
|
this.class = Transaction; |
|
|
|
Transaction.In = TransactionIn; |
|
|
|
Transaction.Out = TransactionOut; |
|
|
|
}; |
|
|
|
this.class = Transaction; |
|
|
|
Transaction.In = TransactionIn; |
|
|
|
Transaction.Out = TransactionOut; |
|
|
|
|
|
|
|
Transaction.prototype.isCoinBase = function () { |
|
|
|
Transaction.prototype.isCoinBase = function () { |
|
|
|
return this.ins.length == 1 && this.ins[0].isCoinBase(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.isStandard = function isStandard() { |
|
|
|
Transaction.prototype.isStandard = function isStandard() { |
|
|
|
var i; |
|
|
|
for (i = 0; i < this.ins.length; i++) { |
|
|
|
if (this.ins[i].getScript().getInType() == "Strange") { |
|
|
@ -134,9 +132,9 @@ function spec(b) { |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.serialize = function serialize() { |
|
|
|
Transaction.prototype.serialize = function serialize() { |
|
|
|
var bufs = []; |
|
|
|
|
|
|
|
var buf = new Buffer(4); |
|
|
@ -159,34 +157,34 @@ function spec(b) { |
|
|
|
|
|
|
|
this._buffer = Buffer.concat(bufs); |
|
|
|
return this._buffer; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.getBuffer = function getBuffer() { |
|
|
|
Transaction.prototype.getBuffer = function getBuffer() { |
|
|
|
if (this._buffer) return this._buffer; |
|
|
|
|
|
|
|
return this.serialize(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.calcHash = function calcHash() { |
|
|
|
Transaction.prototype.calcHash = function calcHash() { |
|
|
|
this.hash = util.twoSha256(this.getBuffer()); |
|
|
|
return this.hash; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.checkHash = function checkHash() { |
|
|
|
Transaction.prototype.checkHash = function checkHash() { |
|
|
|
if (!this.hash || !this.hash.length) return false; |
|
|
|
|
|
|
|
return buffertools.compare(this.calcHash(), this.hash) === 0; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.getHash = function getHash() { |
|
|
|
Transaction.prototype.getHash = function getHash() { |
|
|
|
if (!this.hash || !this.hash.length) { |
|
|
|
this.hash = this.calcHash(); |
|
|
|
} |
|
|
|
return this.hash; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
// convert encoded list of inputs to easy-to-use JS list-of-lists
|
|
|
|
Transaction.prototype.inputs = function inputs() { |
|
|
|
// convert encoded list of inputs to easy-to-use JS list-of-lists
|
|
|
|
Transaction.prototype.inputs = function inputs() { |
|
|
|
var res = []; |
|
|
|
for (var i = 0; i < this.ins.length; i++) { |
|
|
|
var txin = this.ins[i]; |
|
|
@ -196,9 +194,9 @@ function spec(b) { |
|
|
|
} |
|
|
|
|
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Load and cache transaction inputs. |
|
|
|
* |
|
|
|
* This function will try to load the inputs for a transaction. |
|
|
@ -209,15 +207,15 @@ function spec(b) { |
|
|
|
* met (or a timeout occurs.) |
|
|
|
* @param {Function} callback Function to call on completion. |
|
|
|
*/ |
|
|
|
Transaction.prototype.cacheInputs = |
|
|
|
function cacheInputs(blockChain, txStore, wait, callback) { |
|
|
|
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) { |
|
|
|
Transaction.prototype.verify = function verify(txCache, blockChain, callback) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var txIndex = txCache.txIndex; |
|
|
@ -341,22 +339,22 @@ function spec(b) { |
|
|
|
}, |
|
|
|
callback |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) { |
|
|
|
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) { |
|
|
|
return ScriptInterpreter.verify(this.ins[n].getScript(), |
|
|
|
scriptPubKey, |
|
|
|
this, n, 0, |
|
|
|
callback); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Returns an object containing all pubkey hashes affected by this transaction. |
|
|
|
* |
|
|
|
* The return object contains the base64-encoded pubKeyHash values as keys |
|
|
|
* and the original pubKeyHash buffers as values. |
|
|
|
*/ |
|
|
|
Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) { |
|
|
|
Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) { |
|
|
|
// TODO: Function won't consider results cached if there are no affected
|
|
|
|
// accounts.
|
|
|
|
if (!(this.affects && this.affects.length)) { |
|
|
@ -423,22 +421,22 @@ function spec(b) { |
|
|
|
}); |
|
|
|
|
|
|
|
return affectedKeys; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
var OP_CODESEPARATOR = 171; |
|
|
|
var OP_CODESEPARATOR = 171; |
|
|
|
|
|
|
|
var SIGHASH_ALL = 1; |
|
|
|
var SIGHASH_NONE = 2; |
|
|
|
var SIGHASH_SINGLE = 3; |
|
|
|
var SIGHASH_ANYONECANPAY = 80; |
|
|
|
var SIGHASH_ALL = 1; |
|
|
|
var SIGHASH_NONE = 2; |
|
|
|
var SIGHASH_SINGLE = 3; |
|
|
|
var SIGHASH_ANYONECANPAY = 80; |
|
|
|
|
|
|
|
Transaction.SIGHASH_ALL=SIGHASH_ALL; |
|
|
|
Transaction.SIGHASH_NONE=SIGHASH_NONE; |
|
|
|
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE; |
|
|
|
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY; |
|
|
|
Transaction.SIGHASH_ALL=SIGHASH_ALL; |
|
|
|
Transaction.SIGHASH_NONE=SIGHASH_NONE; |
|
|
|
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE; |
|
|
|
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY; |
|
|
|
|
|
|
|
Transaction.prototype.hashForSignature = |
|
|
|
function hashForSignature(script, inIndex, hashType) { |
|
|
|
Transaction.prototype.hashForSignature = |
|
|
|
function hashForSignature(script, inIndex, hashType) { |
|
|
|
if (+inIndex !== inIndex || |
|
|
|
inIndex < 0 || inIndex >= this.ins.length) { |
|
|
|
throw new Error("Input index '"+inIndex+"' invalid or out of bounds "+ |
|
|
@ -540,12 +538,12 @@ function spec(b) { |
|
|
|
buffer = Buffer.concat([buffer, new Buffer([parseInt(hashType), 0, 0, 0])]); |
|
|
|
|
|
|
|
return util.twoSha256(buffer); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Returns an object with the same field names as jgarzik's getblock patch. |
|
|
|
*/ |
|
|
|
Transaction.prototype.getStandardizedObject = function getStandardizedObject() { |
|
|
|
Transaction.prototype.getStandardizedObject = function getStandardizedObject() { |
|
|
|
var tx = { |
|
|
|
hash: util.formatHashFull(this.getHash()), |
|
|
|
version: this.version, |
|
|
@ -587,14 +585,14 @@ function spec(b) { |
|
|
|
tx["out"] = outs; |
|
|
|
|
|
|
|
return tx; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
// Add some Mongoose compatibility functions to the plain object
|
|
|
|
Transaction.prototype.toObject = function toObject() { |
|
|
|
// Add some Mongoose compatibility functions to the plain object
|
|
|
|
Transaction.prototype.toObject = function toObject() { |
|
|
|
return this; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
Transaction.prototype.fromObj = function fromObj(obj) { |
|
|
|
Transaction.prototype.fromObj = function fromObj(obj) { |
|
|
|
var txobj = {}; |
|
|
|
txobj.version = obj.version || 1; |
|
|
|
txobj.lock_time = obj.lock_time || 0; |
|
|
@ -636,9 +634,9 @@ function spec(b) { |
|
|
|
this.version = txobj.version; |
|
|
|
this.ins = txobj.ins; |
|
|
|
this.outs = txobj.outs; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Transaction.prototype.parse = function (parser) { |
|
|
|
Transaction.prototype.parse = function (parser) { |
|
|
|
if (Buffer.isBuffer(parser)) { |
|
|
|
parser = new Parser(parser); |
|
|
|
} |
|
|
@ -672,11 +670,11 @@ function spec(b) { |
|
|
|
|
|
|
|
this.lock_time = parser.word32le(); |
|
|
|
this.calcHash(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
var TransactionInputsCache = exports.TransactionInputsCache = |
|
|
|
function TransactionInputsCache(tx) |
|
|
|
{ |
|
|
|
var TransactionInputsCache = exports.TransactionInputsCache = |
|
|
|
function TransactionInputsCache(tx) |
|
|
|
{ |
|
|
|
var txList = []; |
|
|
|
var txList64 = []; |
|
|
|
var reqOuts = {}; |
|
|
@ -703,10 +701,10 @@ function spec(b) { |
|
|
|
this.txIndex = {}; |
|
|
|
this.requiredOuts = reqOuts; |
|
|
|
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; |
|
|
@ -789,11 +787,11 @@ function spec(b) { |
|
|
|
}, |
|
|
|
self.callback.bind(self) |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
@ -809,8 +807,6 @@ function spec(b) { |
|
|
|
log.err("Callback error after connecting tx inputs: "+ |
|
|
|
(err.stack ? err.stack : err.toString())); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
return Transaction; |
|
|
|
}; |
|
|
|
module.defineClass(spec); |
|
|
|
|
|
|
|
module.exports = require('soop')(Transaction); |
|
|
|