From 274c6e6864c86105c5e8a89429ea8cc5fa8f44a8 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sat, 6 Feb 2016 04:54:38 -0800 Subject: [PATCH] use utxo object instead of tx refs. --- lib/bcoin/address.js | 40 +++++++---- lib/bcoin/block.js | 4 +- lib/bcoin/input.js | 109 +++++++++++++++-------------- lib/bcoin/miner.js | 2 +- lib/bcoin/output.js | 158 +++++++++++++++++++++++++++++++++++++++++-- lib/bcoin/script.js | 40 +++++++++-- lib/bcoin/tx-pool.js | 27 ++++---- lib/bcoin/tx.js | 113 ++++++++++++++----------------- lib/bcoin/wallet.js | 36 ++++++++-- 9 files changed, 370 insertions(+), 159 deletions(-) diff --git a/lib/bcoin/address.js b/lib/bcoin/address.js index 78fa6577..db52c8e6 100644 --- a/lib/bcoin/address.js +++ b/lib/bcoin/address.js @@ -338,14 +338,19 @@ Address.prototype.ownOutput = function ownOutput(tx, index) { var hash = this.getKeyHash(); var key = this.getPublicKey(); var keys = this.keys; - var outputs; + var outputs = tx.outputs; - outputs = tx.outputs.filter(function(output, i) { + if ((tx instanceof bcoin.output) || (tx instanceof bcoin.output.prev)) + outputs = [tx]; + + outputs = outputs.filter(function(output, i) { var s = output.script; if (index != null && index !== i) return false; + return output.testScript(key, hash, keys, scriptHash, null); + if (bcoin.script.isPubkey(s, key)) return true; @@ -375,17 +380,24 @@ Address.prototype.ownInput = function ownInput(tx, index) { var key = this.getPublicKey(); var redeem = this.getScript(); var keys = this.keys; - var inputs; + var inputs = tx.inputs; - inputs = tx.inputs.filter(function(input, i) { - if (!input.prevout.tx && this.tx._all[input.prevout.hash]) - input.prevout.tx = this.tx._all[input.prevout.hash]; + if (tx instanceof bcoin.input) { + inputs = [tx]; + tx = null; + } + if (tx) + this._wallet.fillPrevout(tx); + + inputs = inputs.filter(function(input, i) { if (index != null && index !== i) return false; - if (input.prevout.tx) - return !!this.ownOutput(input.prevout.tx, input.prevout.index); + if (input.output) + return !!this.ownOutput(input.output); + + return input.testScript(key, redeem, null); // if (bcoin.script.isPubkeyInput(input.script, key, tx, i)) // return true; @@ -416,10 +428,10 @@ Address.prototype.scriptInputs = function scriptInputs(tx) { var redeem = this.getScript(); return tx.inputs.reduce(function(total, input, i) { - if (!input.prevout.tx) + if (!input.output) return total; - if (!self.ownOutput(input.prevout.tx, input.prevout.index)) + if (!self.ownOutput(input.output)) return total; if (tx.scriptInput(i, publicKey, redeem)) @@ -438,10 +450,10 @@ Address.prototype.signInputs = function signInputs(tx, type) { return 0; return tx.inputs.reduce(function(total, input, i) { - if (!input.prevout.tx) + if (!input.output) return total; - if (!self.ownOutput(input.prevout.tx, input.prevout.index)) + if (!self.ownOutput(input.output)) return total; if (tx.signInput(i, key, type)) @@ -463,10 +475,10 @@ Address.prototype.sign = function sign(tx, type) { // Add signature script to each input return tx.inputs.reduce(function(total, input, i) { // Filter inputs that this wallet own - if (!input.prevout.tx) + if (!input.output) return total; - if (!self.ownOutput(input.prevout.tx, input.prevout.index)) + if (!self.ownOutput(input.output)) return total; if (tx.scriptSig(i, key, publicKey, redeem, type)) diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index e9c97c4e..3dc0a3a6 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -459,10 +459,10 @@ Block.prototype.verifyContext = function verifyContext() { // We need the previous output in order // to verify the script. - if (!input.prevout.tx) + if (!input.output) continue; - assert(input.prevout.tx); + assert(input.output); // Verify the script if (!tx.verify(j, true, flags)) { diff --git a/lib/bcoin/input.js b/lib/bcoin/input.js index 202fe303..f17eb67b 100644 --- a/lib/bcoin/input.js +++ b/lib/bcoin/input.js @@ -22,17 +22,21 @@ function Input(options) { prevout = options.prevout || options.out; - this.tx = options.tx; - this.prevout = { - tx: prevout.tx || null, hash: prevout.hash, - index: prevout.index + index: prevout.index, + rhash: prevout.rhash }; + if (options.output) + this.output = bcoin.output.prev(options.output); + if (utils.isBuffer(this.prevout.hash)) this.prevout.hash = utils.toHex(this.prevout.hash); + if (!this.prevout.rhash) + this.prevout.rhash = utils.toHex(this.prevout.hash); + this.script = options.script ? options.script.slice() : []; this.sequence = options.sequence == null ? 0xffffffff : options.sequence; @@ -91,7 +95,7 @@ Input.prototype.__defineGetter__('key', function() { return this.keys[0]; }); -Input.prototype.__defineGetter__('hash', function() { +Input.prototype.__defineGetter__('hash160', function() { return this.data.scriptHash || this.hashes[0]; }); @@ -153,22 +157,12 @@ Input.prototype.__defineGetter__('text', function() { return this.data.text; }); -Input.prototype.__defineGetter__('output', function() { - if (!this.prevout.tx) - return; - return this.prevout.tx.outputs[this.prevout.index]; -}); - Input.prototype.__defineGetter__('value', function() { if (!this.output) return; return this.output.value; }); -Input.prototype.__defineGetter__('tx', function() { - return this.prevout.tx; -}); - Input.prototype.__defineGetter__('addr', function() { return this.address; }); @@ -238,7 +232,7 @@ Input.getData = function getData(input) { def.prev = input.prevout.hash; def.index = input.prevout.index; - if (+input.prevout.hash === 0) { + if (input.isCoinbase()) { data = bcoin.script.getCoinbaseData(input.script); return utils.merge(def, data, { type: 'coinbase', @@ -307,45 +301,62 @@ Input.prototype.getLocktime = function getLocktime() { return bcoin.script.getLocktime(redeem); }; -Input.prototype.createScript = function createScript(pub, redeem) { - return this.tx.scriptInput(this, pub, redeem); -}; - -Input.prototype.signatureHash = function signatureHash(s, type) { - return this.tx.signatureHash(this, s, type); -}; - -Input.prototype.createSignature = function createSignature(key, type) { - return this.tx.createSignature(this, key, type); -}; - -Input.prototype.sign = function sign(key, type) { - return this.tx.signInput(this, key, type); -}; - -Input.prototype.scriptSig = function scriptSig(key, pub, redeem, type) { - return this.tx.scriptSig(this, key, pub, redeem, type); -}; - -Input.prototype.isSigned = function isSigned(required) { - return this.tx.isSigned(this, required); -}; - -Input.prototype.verify = function verify(force, flags) { - return this.tx.verify(this, force, flags); -}; - Input.prototype.isCoinbase = function isCoinbase() { - return this.tx.isCoinbase(); + return +this.prevout.hash === 0; }; -Input.prototype.test = function test(addressTable, collect) { - return this.tx.testInputs(addressTable, this, collect); +Input.prototype.testScript = function testScript(key, redeem, type) { + // if (!type || type === 'pubkey') { + // if (key) { + // if (bcoin.script.isPubkeyInput(this.script, key, tx, i)) + // return true; + // } + // } + + if (!type || type === 'pubkeyhash') { + if (key) { + if (bcoin.script.isPubkeyhashInput(this.script, key)) + return true; + } + } + + // if (!type || type === 'multisig') { + // if (keys) { + // if (bcoin.script.isMultisigInput(input.script, keys, tx, i)) + // return true; + // } + // } + + if (!type || type === 'scripthash') { + if (redeem) { + if (bcoin.script.isScripthashInput(this.script, redeem)) + return true; + } + } + + return false; +}; + +Input.prototype.test = function test(addressTable) { + var data = this.getData(); + var i; + + if (data.scriptAddress) { + if (addressTable[data.scriptAddress] != null) + return true; + } + + for (i = 0; i < data.addresses.length; i++) { + if (addressTable[data.addresses[i]] != null) + return true; + } + + return false; }; Input.prototype.getSigops = function getSigops(scriptHash, accurate) { var n = bcoin.script.getSigops(this.script, accurate); - if (scriptHash && !this.tx.isCoinbase()) + if (scriptHash && !this.isCoinbase()) n += bcoin.script.getScripthashSigops(this.script); return n; }; @@ -356,7 +367,7 @@ Input.prototype.inspect = function inspect() { : { type: 'unknown', value: '0.0' }; output.hash = this.prevout.hash; - output.rhash = utils.revHex(this.prevout.hash); + output.rhash = this.prevout.rhash; output.index = this.prevout.index; return { diff --git a/lib/bcoin/miner.js b/lib/bcoin/miner.js index bfce3524..2794a92e 100644 --- a/lib/bcoin/miner.js +++ b/lib/bcoin/miner.js @@ -142,7 +142,7 @@ Miner.prototype.addTX = function addTX(tx) { var full, ts; full = this.index.inputs.every(function(input) { - return !!input.prevout.tx; + return !!input.output; }); // Cannot calculate fee if we don't have the prev_out. diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index 3d62de33..1a7be03a 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -6,6 +6,7 @@ var bn = require('bn.js'); var bcoin = require('../bcoin'); +var inherits = require('inherits'); var utils = bcoin.utils; var assert = utils.assert; var constants = bcoin.protocol.constants; @@ -25,7 +26,6 @@ function Output(options) { if (typeof value === 'number' && (value | 0) === value) value = new bn(value); - this.tx = options.tx; this.value = utils.satoshi(value || new bn(0)); this.script = options.script ? options.script.slice() : []; @@ -66,7 +66,7 @@ Output.prototype.__defineGetter__('key', function() { return this.keys[0]; }); -Output.prototype.__defineGetter__('hash', function() { +Output.prototype.__defineGetter__('hash160', function() { return this.data.scriptHash || this.hashes[0]; }); @@ -222,12 +222,53 @@ Output.prototype.getID = function getID() { return '[' + this.type + ':' + hash.slice(0, 7) + ']'; }; -Output.prototype.createScript = function createScript(options) { - return this.tx.scriptOutput(this, options); +Output.prototype.testScript = function testScript(key, hash, keys, scriptHash, type) { + if (!type || type === 'pubkey') { + if (key) { + if (bcoin.script.isPubkey(this.script, key)) + return true; + } + } + + if (!type || type === 'pubkeyhash') { + if (hash) { + if (bcoin.script.isPubkeyhash(this.script, hash)) + return true; + } + } + + if (!type || type === 'multisig') { + if (keys) { + if (bcoin.script.isMultisig(this.script, keys)) + return true; + } + } + + if (!type || type === 'scripthash') { + if (scriptHash) { + if (bcoin.script.isScripthash(this.script, scriptHash)) + return true; + } + } + + return false; }; -Output.prototype.test = function test(addressTable, collect) { - return this.tx.testOutputs(addressTable, this, collect); +Output.prototype.test = function test(addressTable) { + var data = this.getData(); + var i; + + if (data.scriptAddress) { + if (addressTable[data.scriptAddress] != null) + return true; + } + + for (i = 0; i < data.addresses.length; i++) { + if (addressTable[data.addresses[i]] != null) + return true; + } + + return false; }; Output.prototype.getSigops = function getSigops(accurate) { @@ -251,8 +292,111 @@ Output.prototype.inspect = function inspect() { }; }; +// This is basically a UTXO/Coin object. It is immutable once instantiated. It +// needs to store 5 properties: the tx hash, output index, output value, output +// script, and the block height the transaction was mined (to later calculate +// age). + +function Prevout(tx, index) { + var options; + + if (!(this instanceof Prevout)) + return new Prevout(tx, index); + + if (tx instanceof Prevout) + return tx; + + if (tx instanceof bcoin.tx) { + this.hash = tx.hash('hex'); + this.index = index; + this.value = tx.outputs[index].value; + this.script = tx.outputs[index].script; + this.height = tx.getHeight(); + } else { + options = tx; + this.hash = options.hash; + this.index = options.index; + this.value = options.value; + this.script = options.script; + this.height = options.height; + } + + if (utils.isBuffer(this.hash)) + this.hash = utils.toHex(this.hash); + + assert(typeof this.hash === 'string'); + assert(utils.isFinite(this.index)); + assert(this.value instanceof bn); + assert(Array.isArray(this.script)); + assert(utils.isFinite(this.height)); + + Object.freeze(this); +} + +inherits(Prevout, Output); + +Prevout.prototype.__defineGetter__('chain', function() { + return this._chain || bcoin.chain.global; +}); + +Prevout.prototype.getConfirmations = function getConfirmations() { + var top; + + if (!this.chain) + return 0; + + top = this.chain.height(); + + if (this.height === -1) + return 0; + + return top - this.height + 1; +}; + +Prevout.prototype.__defineGetter__('confirmations', function() { + return this.getConfirmations(); +}); + +Prevout.prototype.getAge = function getAge() { + var age = this.getConfirmations(); + + if (age === -1) + age = 0; + + if (age !== 0) + age += 1; + + return age; +}; + +Prevout.prototype.__defineGetter__('age', function() { + return this.getAge(); +}); + +Prevout.prototype.toJSON = function toJSON() { + return { + hash: this.hash, + index: this.index, + value: utils.btc(this.value), + script: utils.toHex(bcoin.script.encode(this.script)), + height: this.height + }; +}; + +Prevout.fromJSON = function fromJSON(json) { + return new Prevout({ + hash: json.hash, + index: json.index, + value: utils.satoshi(json.value), + script: bcoin.script.decode(utils.toArray(json.script, 'hex')), + height: json.height + }); +}; + /** * Expose */ -module.exports = Output; +exports = Output; +exports.prev = Prevout; +module.exports = exports; diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 222d2d4b..fa713a10 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -1307,12 +1307,16 @@ script.getInputData = function getData(s, prev) { // We could call _getInputData, but // we really only need the signatures. if (output.type === 'pubkey') { - output.signatures = [s[0]]; + if (s.length >= 1) + output.signatures = [s[0]]; } else if (output.type === 'pubkeyhash') { - output.signatures = [s[0]]; - output.keys = [s[1]]; + if (s.length >= 2) { + output.signatures = [s[0]]; + output.keys = [s[1]]; + } } else if (output.type === 'multisig') { - output.signatures = s.slice(1); + if (s.length >= 2) + output.signatures = s.slice(1); } else if (output.type === 'scripthash') { // Scripthash is the only case where // we get more data from the input @@ -1345,6 +1349,13 @@ script._getInputData = function _getInputData(s, type) { assert(typeof type === 'string'); if (type === 'pubkey') { + if (s.length < 1) { + return { + type: 'pubkey', + side: 'input', + none: true + }; + } sig = s[0]; return { type: 'pubkey', @@ -1355,6 +1366,13 @@ script._getInputData = function _getInputData(s, type) { } if (type === 'pubkeyhash') { + if (s.length < 2) { + return { + type: 'pubkeyhash', + side: 'input', + none: true + }; + } sig = s[0]; key = s[1]; hash = bcoin.wallet.key2hash(key); @@ -1370,6 +1388,13 @@ script._getInputData = function _getInputData(s, type) { } if (type === 'multisig') { + if (s.length < 2) { + return { + type: 'multisig', + side: 'input', + none: true + }; + } sig = s.slice(1); return { type: 'multisig', @@ -1381,6 +1406,13 @@ script._getInputData = function _getInputData(s, type) { } if (type === 'scripthash') { + if (s.length < 1) { + return { + type: 'scripthash', + side: 'input', + none: true + }; + } raw = s[s.length - 1]; redeem = script.decode(raw); locktime = script.getLocktime(redeem); diff --git a/lib/bcoin/tx-pool.js b/lib/bcoin/tx-pool.js index c59577e8..9efed078 100644 --- a/lib/bcoin/tx-pool.js +++ b/lib/bcoin/tx-pool.js @@ -86,6 +86,8 @@ TXPool.prototype.add = function add(tx, noWrite, strict) { var i, input, key, unspent, index, orphan; var out, key, orphans, some; + this._wallet.fillPrevout(tx); + if (strict) { if (!this._wallet.ownInput(tx) && !this._wallet.ownOutput(tx)) return false; @@ -120,17 +122,14 @@ TXPool.prototype.add = function add(tx, noWrite, strict) { key = input.prevout.hash + '/' + input.prevout.index; unspent = this._unspent[key]; - if (!input.prevout.tx && this._all[input.prevout.hash]) - input.prevout.tx = this._all[input.prevout.hash]; - if (unspent) { // Add TX to inputs and spend money - index = tx._inputIndex(unspent.tx.hash('hex'), unspent.index); + index = tx._inputIndex(unspent.hash, unspent.index); assert(index !== -1); assert(tx.inputs[index] === input); - assert(tx.inputs[index].prevout.hash === unspent.tx.hash('hex')); + assert(tx.inputs[index].prevout.hash === unspent.hash); assert(tx.inputs[index].prevout.index === unspent.index); - input.prevout.tx = unspent.tx; + input.output = unspent; // Skip invalid transactions if (!tx.verify(index)) @@ -149,8 +148,8 @@ TXPool.prototype.add = function add(tx, noWrite, strict) { // signature checking code to ownInput for p2sh and p2pk, // we could in theory use ownInput here (and down below) // instead. - if (input.prevout.tx) { - if (!this._wallet.ownOutput(input.prevout.tx, input.prevout.index)) + if (input.output) { + if (!this._wallet.ownOutput(input.output)) continue; } @@ -177,7 +176,7 @@ TXPool.prototype.add = function add(tx, noWrite, strict) { assert(index !== -1); assert(orphan.tx.inputs[index].prevout.hash === tx.hash('hex')); assert(orphan.tx.inputs[index].prevout.index === i); - orphan.tx.inputs[index].prevout.tx = tx; + orphan.tx.inputs[index].output = bcoin.output.prev(tx, i); // Verify that input script is correct, if not - add output to unspent // and remove orphan from storage @@ -211,7 +210,7 @@ TXPool.prototype.add = function add(tx, noWrite, strict) { delete this._orphans[key]; if (!orphans) { - this._unspent[key] = { tx: tx, index: i }; + this._unspent[key] = bcoin.output.prev(tx, i); updated = true; } } @@ -327,11 +326,11 @@ TXPool.prototype._addInput = function _addInput(tx, i, remove) { var input = tx.inputs[i]; var prev, address; - if (!this._wallet.ownOutput(input.prevout.tx, input.prevout.index)) - return; - assert(input.output); + if (!this._wallet.ownOutput(input.output)) + return; + prev = input.output; address = prev.getAddress(); @@ -378,7 +377,7 @@ TXPool.prototype.getUnspent = function getUnspent(address) { return Object.keys(this._unspent).map(function(key) { return this._unspent[key]; }, this).filter(function(item) { - return address.ownOutput(item.tx, item.index); + return address.ownOutput(item); }); }; diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 83bf96e2..5d1efa64 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -128,14 +128,11 @@ TX.prototype.input = TX.prototype.addInput; TX.prototype._addInput = function _addInput(options, index) { var input, ex, i, prevout; - if (options instanceof TX) - options = { prevout: { tx: options, index: index } }; - else if (typeof options === 'string' || utils.isBuffer(options)) - options = { prevout: { hash: options, index: index } }; - else if (!options.prevout) - options = { prevout: options, script: options.script, sequence: options.sequence }; - else - options = options; + if (options instanceof TX) { + options = { tx: options, index: index }; + } else if (typeof options === 'string' || utils.isBuffer(options)) { + options = { hash: options, index: index }; + } if (options.out) options.prevout = options.out; @@ -143,16 +140,37 @@ TX.prototype._addInput = function _addInput(options, index) { if (options.seq != null) options.sequence = options.seq; - if (options.prevout.tx) - options.prevout.hash = options.prevout.tx.hash('hex'); + if (!options.prevout) { + if (options instanceof bcoin.output.prev) { + options = { + prevout: { hash: options.hash, index: options.index }, + output: options + }; + } else if (options.tx) { + var prev = bcoin.output.prev(options.tx, options.index); + options = { + prevout: { hash: prev.hash, index: prev.index }, + output: prev, + script: options.script, + sequence: options.sequence + }; + } else if (options.hash) { + options = { + prevout: { hash: options.hash, index: options.index }, + output: options.output, + script: options.script, + sequence: options.sequence + }; + } + } input = bcoin.input({ tx: this, prevout: { - tx: options.prevout.tx, hash: options.prevout.hash, index: options.prevout.index }, + output: options.output, script: options.script, sequence: options.sequence }); @@ -161,8 +179,8 @@ TX.prototype._addInput = function _addInput(options, index) { i = this._inputIndex(input.prevout.hash, input.prevout.index); if (i !== -1) { ex = this.inputs[i]; - input.prevout.tx = input.prevout.tx || ex.prevout.tx; - input.sequence = input.sequence || ex.sequence; + input.output = input.output || ex.output; + input.sequence = input.sequence != null ? input.sequence : ex.sequence; input.script = input.script.length ? input.script : ex.script; this.inputs[i] = input; } else { @@ -886,10 +904,6 @@ TX.prototype.verify = function verify(index, force, flags) { if (!input.output) return false; - // Somethis is very wrong if this is - // not the case. - assert.equal(input.prevout.tx.hash('hex'), input.prevout.hash); - return bcoin.script.verify(input.script, input.output.script, this, i, flags); }, this); }; @@ -1015,7 +1029,7 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) { // Oldest unspents first unspent = unspent.slice().sort(function(a, b) { - return b.tx.getConfirmations() - a.tx.getConfirmations(); + return a.height - b.height; }); function addInput(unspent) { @@ -1289,7 +1303,7 @@ TX.prototype.getTargetLocktime = function getTargetLocktime() { TX.prototype.testInputs = function testInputs(addressTable, index, collect) { var inputs = []; - var i, input, j, addresses, scriptAddress; + var i, input; if (typeof addressTable === 'string') addressTable = [addressTable]; @@ -1313,24 +1327,10 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) { input = this.inputs[i]; - addresses = input.getAddresses(); - if (addresses) { - for (j = 0; j < addresses.length; j++) { - if (addressTable[addresses[j]] != null) { - if (!collect) - return true; - inputs.push(input); - } - } - } - - scriptAddress = input.getScriptAddress(); - if (scriptAddress) { - if (addressTable[scriptAddress] != null) { - if (!collect) - return true; - inputs.push(input); - } + if (input.test(addressTable)) { + if (!collect) + return true; + inputs.push(input); } } @@ -1345,7 +1345,7 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) { TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) { var outputs = []; - var i, output, data, j, addresses, scriptAddress; + var i, output; if (typeof addressTable === 'string') addressTable = [addressTable]; @@ -1369,24 +1369,10 @@ TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) { output = this.outputs[i]; - addresses = output.getAddresses(); - if (addresses) { - for (j = 0; j < addresses.length; j++) { - if (addressTable[addresses[j]] != null) { - if (!collect) - return true; - outputs.push(output); - } - } - } - - scriptAddress = output.getScriptAddress(); - if (scriptAddress) { - if (addressTable[scriptAddress] != null) { - if (!collect) - return true; - outputs.push(output); - } + if (output.test(addressTable)) { + if (!collect) + return true; + outputs.push(output); } } @@ -1438,7 +1424,7 @@ TX.prototype.hasPrevout = function hasPrevout() { return false; return this.inputs.every(function(input) { - return !!input.prevout.tx; + return !!input.output; }); }; @@ -1458,9 +1444,9 @@ TX.prototype.fillPrevout = function fillPrevout(txs) { } inputs = this.inputs.filter(function(input) { - if (!input.prevout.tx && txs[input.prevout.hash]) - input.prevout.tx = txs[input.prevout.hash]; - return !!input.prevout.tx; + if (!input.output && txs[input.prevout.hash]) + input.output = bcoin.output.prev(txs[input.prevout.hash], input.prevout.index); + return !!input.output; }, this); return inputs.length === this.inputs.length; @@ -1646,10 +1632,10 @@ TX.prototype.getPriority = function getPriority() { for (i = 0; i < this.inputs.length; i++) { input = this.inputs[i]; - if (!input.prevout.tx) + if (!input.output) return constants.tx.freeThreshold.clone(); - age = input.prevout.tx.getConfirmations(); + age = input.output.getConfirmations(); if (age === -1) age = 0; @@ -1749,7 +1735,8 @@ TX.prototype.inspect = function inspect() { copy.fee = utils.btc(this.getFee()); copy.height = this.getHeight(); copy.confirmations = this.getConfirmations(); - // copy.priority = this.getPriority().toString(10); + if (this.hasPrevout()) + copy.priority = this.getPriority().toString(10); copy.date = new Date((copy.ts || 0) * 1000).toISOString(); if (copy.hardFee) copy.hardFee = utils.btc(copy.hardFee); diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index 7b211702..fcb33ccd 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -813,11 +813,39 @@ Wallet.prototype.getAddress = function getAddress() { }; Wallet.prototype.ownInput = function ownInput(tx, index) { + if (tx instanceof bcoin.input) { + var input = tx; + var scriptAddress = input.getScriptAddress(); + if (this._addressTable[scriptAddress] != null) + return true; + var addresses = input.getAddresses(); + var address; + for (var i = 0; i < addresses.length; i++) { + address = addresses[i]; + if (this._addressTable[address] != null) + return true; + } + return false; + } this.fillPrevout(tx); return tx.testInputs(this._addressTable, index, true); }; Wallet.prototype.ownOutput = function ownOutput(tx, index) { + if ((tx instanceof bcoin.output) || (tx instanceof bcoin.output.prev)) { + var output = tx; + var scriptAddress = output.getScriptAddress(); + if (this._addressTable[scriptAddress] != null) + return true; + var addresses = output.getAddresses(); + var address; + for (var i = 0; i < addresses.length; i++) { + address = addresses[i]; + if (this._addressTable[address] != null) + return true; + } + return false; + } return tx.testOutputs(this._addressTable, index, true); }; @@ -831,13 +859,11 @@ Wallet.prototype.fill = function fill(tx, address, fee) { unspent = this.getUnspent(); - items = unspent.filter(function(item) { - var output = item.tx.outputs[item.index]; - - if (bcoin.script.isScripthash(output.script)) + items = unspent.filter(function(coin) { + if (bcoin.script.isScripthash(coin.script)) return this.type === 'scripthash'; - if (bcoin.script.isMultisig(output.script)) + if (bcoin.script.isMultisig(coin.script)) return this.type === 'multisig'; return true;