use utxo object instead of tx refs.
This commit is contained in:
parent
26f1e44eb3
commit
274c6e6864
@ -338,14 +338,19 @@ Address.prototype.ownOutput = function ownOutput(tx, index) {
|
|||||||
var hash = this.getKeyHash();
|
var hash = this.getKeyHash();
|
||||||
var key = this.getPublicKey();
|
var key = this.getPublicKey();
|
||||||
var keys = this.keys;
|
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;
|
var s = output.script;
|
||||||
|
|
||||||
if (index != null && index !== i)
|
if (index != null && index !== i)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
return output.testScript(key, hash, keys, scriptHash, null);
|
||||||
|
|
||||||
if (bcoin.script.isPubkey(s, key))
|
if (bcoin.script.isPubkey(s, key))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -375,17 +380,24 @@ Address.prototype.ownInput = function ownInput(tx, index) {
|
|||||||
var key = this.getPublicKey();
|
var key = this.getPublicKey();
|
||||||
var redeem = this.getScript();
|
var redeem = this.getScript();
|
||||||
var keys = this.keys;
|
var keys = this.keys;
|
||||||
var inputs;
|
var inputs = tx.inputs;
|
||||||
|
|
||||||
inputs = tx.inputs.filter(function(input, i) {
|
if (tx instanceof bcoin.input) {
|
||||||
if (!input.prevout.tx && this.tx._all[input.prevout.hash])
|
inputs = [tx];
|
||||||
input.prevout.tx = this.tx._all[input.prevout.hash];
|
tx = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tx)
|
||||||
|
this._wallet.fillPrevout(tx);
|
||||||
|
|
||||||
|
inputs = inputs.filter(function(input, i) {
|
||||||
if (index != null && index !== i)
|
if (index != null && index !== i)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (input.prevout.tx)
|
if (input.output)
|
||||||
return !!this.ownOutput(input.prevout.tx, input.prevout.index);
|
return !!this.ownOutput(input.output);
|
||||||
|
|
||||||
|
return input.testScript(key, redeem, null);
|
||||||
|
|
||||||
// if (bcoin.script.isPubkeyInput(input.script, key, tx, i))
|
// if (bcoin.script.isPubkeyInput(input.script, key, tx, i))
|
||||||
// return true;
|
// return true;
|
||||||
@ -416,10 +428,10 @@ Address.prototype.scriptInputs = function scriptInputs(tx) {
|
|||||||
var redeem = this.getScript();
|
var redeem = this.getScript();
|
||||||
|
|
||||||
return tx.inputs.reduce(function(total, input, i) {
|
return tx.inputs.reduce(function(total, input, i) {
|
||||||
if (!input.prevout.tx)
|
if (!input.output)
|
||||||
return total;
|
return total;
|
||||||
|
|
||||||
if (!self.ownOutput(input.prevout.tx, input.prevout.index))
|
if (!self.ownOutput(input.output))
|
||||||
return total;
|
return total;
|
||||||
|
|
||||||
if (tx.scriptInput(i, publicKey, redeem))
|
if (tx.scriptInput(i, publicKey, redeem))
|
||||||
@ -438,10 +450,10 @@ Address.prototype.signInputs = function signInputs(tx, type) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return tx.inputs.reduce(function(total, input, i) {
|
return tx.inputs.reduce(function(total, input, i) {
|
||||||
if (!input.prevout.tx)
|
if (!input.output)
|
||||||
return total;
|
return total;
|
||||||
|
|
||||||
if (!self.ownOutput(input.prevout.tx, input.prevout.index))
|
if (!self.ownOutput(input.output))
|
||||||
return total;
|
return total;
|
||||||
|
|
||||||
if (tx.signInput(i, key, type))
|
if (tx.signInput(i, key, type))
|
||||||
@ -463,10 +475,10 @@ Address.prototype.sign = function sign(tx, type) {
|
|||||||
// Add signature script to each input
|
// Add signature script to each input
|
||||||
return tx.inputs.reduce(function(total, input, i) {
|
return tx.inputs.reduce(function(total, input, i) {
|
||||||
// Filter inputs that this wallet own
|
// Filter inputs that this wallet own
|
||||||
if (!input.prevout.tx)
|
if (!input.output)
|
||||||
return total;
|
return total;
|
||||||
|
|
||||||
if (!self.ownOutput(input.prevout.tx, input.prevout.index))
|
if (!self.ownOutput(input.output))
|
||||||
return total;
|
return total;
|
||||||
|
|
||||||
if (tx.scriptSig(i, key, publicKey, redeem, type))
|
if (tx.scriptSig(i, key, publicKey, redeem, type))
|
||||||
|
|||||||
@ -459,10 +459,10 @@ Block.prototype.verifyContext = function verifyContext() {
|
|||||||
|
|
||||||
// We need the previous output in order
|
// We need the previous output in order
|
||||||
// to verify the script.
|
// to verify the script.
|
||||||
if (!input.prevout.tx)
|
if (!input.output)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
assert(input.prevout.tx);
|
assert(input.output);
|
||||||
|
|
||||||
// Verify the script
|
// Verify the script
|
||||||
if (!tx.verify(j, true, flags)) {
|
if (!tx.verify(j, true, flags)) {
|
||||||
|
|||||||
@ -22,17 +22,21 @@ function Input(options) {
|
|||||||
|
|
||||||
prevout = options.prevout || options.out;
|
prevout = options.prevout || options.out;
|
||||||
|
|
||||||
this.tx = options.tx;
|
|
||||||
|
|
||||||
this.prevout = {
|
this.prevout = {
|
||||||
tx: prevout.tx || null,
|
|
||||||
hash: prevout.hash,
|
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))
|
if (utils.isBuffer(this.prevout.hash))
|
||||||
this.prevout.hash = utils.toHex(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.script = options.script ? options.script.slice() : [];
|
||||||
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
|
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
|
||||||
|
|
||||||
@ -91,7 +95,7 @@ Input.prototype.__defineGetter__('key', function() {
|
|||||||
return this.keys[0];
|
return this.keys[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
Input.prototype.__defineGetter__('hash', function() {
|
Input.prototype.__defineGetter__('hash160', function() {
|
||||||
return this.data.scriptHash || this.hashes[0];
|
return this.data.scriptHash || this.hashes[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,22 +157,12 @@ Input.prototype.__defineGetter__('text', function() {
|
|||||||
return this.data.text;
|
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() {
|
Input.prototype.__defineGetter__('value', function() {
|
||||||
if (!this.output)
|
if (!this.output)
|
||||||
return;
|
return;
|
||||||
return this.output.value;
|
return this.output.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
Input.prototype.__defineGetter__('tx', function() {
|
|
||||||
return this.prevout.tx;
|
|
||||||
});
|
|
||||||
|
|
||||||
Input.prototype.__defineGetter__('addr', function() {
|
Input.prototype.__defineGetter__('addr', function() {
|
||||||
return this.address;
|
return this.address;
|
||||||
});
|
});
|
||||||
@ -238,7 +232,7 @@ Input.getData = function getData(input) {
|
|||||||
def.prev = input.prevout.hash;
|
def.prev = input.prevout.hash;
|
||||||
def.index = input.prevout.index;
|
def.index = input.prevout.index;
|
||||||
|
|
||||||
if (+input.prevout.hash === 0) {
|
if (input.isCoinbase()) {
|
||||||
data = bcoin.script.getCoinbaseData(input.script);
|
data = bcoin.script.getCoinbaseData(input.script);
|
||||||
return utils.merge(def, data, {
|
return utils.merge(def, data, {
|
||||||
type: 'coinbase',
|
type: 'coinbase',
|
||||||
@ -307,45 +301,62 @@ Input.prototype.getLocktime = function getLocktime() {
|
|||||||
return bcoin.script.getLocktime(redeem);
|
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() {
|
Input.prototype.isCoinbase = function isCoinbase() {
|
||||||
return this.tx.isCoinbase();
|
return +this.prevout.hash === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Input.prototype.test = function test(addressTable, collect) {
|
Input.prototype.testScript = function testScript(key, redeem, type) {
|
||||||
return this.tx.testInputs(addressTable, this, collect);
|
// 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) {
|
Input.prototype.getSigops = function getSigops(scriptHash, accurate) {
|
||||||
var n = bcoin.script.getSigops(this.script, accurate);
|
var n = bcoin.script.getSigops(this.script, accurate);
|
||||||
if (scriptHash && !this.tx.isCoinbase())
|
if (scriptHash && !this.isCoinbase())
|
||||||
n += bcoin.script.getScripthashSigops(this.script);
|
n += bcoin.script.getScripthashSigops(this.script);
|
||||||
return n;
|
return n;
|
||||||
};
|
};
|
||||||
@ -356,7 +367,7 @@ Input.prototype.inspect = function inspect() {
|
|||||||
: { type: 'unknown', value: '0.0' };
|
: { type: 'unknown', value: '0.0' };
|
||||||
|
|
||||||
output.hash = this.prevout.hash;
|
output.hash = this.prevout.hash;
|
||||||
output.rhash = utils.revHex(this.prevout.hash);
|
output.rhash = this.prevout.rhash;
|
||||||
output.index = this.prevout.index;
|
output.index = this.prevout.index;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -142,7 +142,7 @@ Miner.prototype.addTX = function addTX(tx) {
|
|||||||
var full, ts;
|
var full, ts;
|
||||||
|
|
||||||
full = this.index.inputs.every(function(input) {
|
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.
|
// Cannot calculate fee if we don't have the prev_out.
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
var bn = require('bn.js');
|
var bn = require('bn.js');
|
||||||
var bcoin = require('../bcoin');
|
var bcoin = require('../bcoin');
|
||||||
|
var inherits = require('inherits');
|
||||||
var utils = bcoin.utils;
|
var utils = bcoin.utils;
|
||||||
var assert = utils.assert;
|
var assert = utils.assert;
|
||||||
var constants = bcoin.protocol.constants;
|
var constants = bcoin.protocol.constants;
|
||||||
@ -25,7 +26,6 @@ function Output(options) {
|
|||||||
if (typeof value === 'number' && (value | 0) === value)
|
if (typeof value === 'number' && (value | 0) === value)
|
||||||
value = new bn(value);
|
value = new bn(value);
|
||||||
|
|
||||||
this.tx = options.tx;
|
|
||||||
this.value = utils.satoshi(value || new bn(0));
|
this.value = utils.satoshi(value || new bn(0));
|
||||||
this.script = options.script ? options.script.slice() : [];
|
this.script = options.script ? options.script.slice() : [];
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ Output.prototype.__defineGetter__('key', function() {
|
|||||||
return this.keys[0];
|
return this.keys[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
Output.prototype.__defineGetter__('hash', function() {
|
Output.prototype.__defineGetter__('hash160', function() {
|
||||||
return this.data.scriptHash || this.hashes[0];
|
return this.data.scriptHash || this.hashes[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -222,12 +222,53 @@ Output.prototype.getID = function getID() {
|
|||||||
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
|
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
|
||||||
};
|
};
|
||||||
|
|
||||||
Output.prototype.createScript = function createScript(options) {
|
Output.prototype.testScript = function testScript(key, hash, keys, scriptHash, type) {
|
||||||
return this.tx.scriptOutput(this, options);
|
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) {
|
Output.prototype.test = function test(addressTable) {
|
||||||
return this.tx.testOutputs(addressTable, this, collect);
|
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) {
|
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
|
* Expose
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = Output;
|
exports = Output;
|
||||||
|
exports.prev = Prevout;
|
||||||
|
module.exports = exports;
|
||||||
|
|||||||
@ -1307,12 +1307,16 @@ script.getInputData = function getData(s, prev) {
|
|||||||
// We could call _getInputData, but
|
// We could call _getInputData, but
|
||||||
// we really only need the signatures.
|
// we really only need the signatures.
|
||||||
if (output.type === 'pubkey') {
|
if (output.type === 'pubkey') {
|
||||||
output.signatures = [s[0]];
|
if (s.length >= 1)
|
||||||
|
output.signatures = [s[0]];
|
||||||
} else if (output.type === 'pubkeyhash') {
|
} else if (output.type === 'pubkeyhash') {
|
||||||
output.signatures = [s[0]];
|
if (s.length >= 2) {
|
||||||
output.keys = [s[1]];
|
output.signatures = [s[0]];
|
||||||
|
output.keys = [s[1]];
|
||||||
|
}
|
||||||
} else if (output.type === 'multisig') {
|
} else if (output.type === 'multisig') {
|
||||||
output.signatures = s.slice(1);
|
if (s.length >= 2)
|
||||||
|
output.signatures = s.slice(1);
|
||||||
} else if (output.type === 'scripthash') {
|
} else if (output.type === 'scripthash') {
|
||||||
// Scripthash is the only case where
|
// Scripthash is the only case where
|
||||||
// we get more data from the input
|
// we get more data from the input
|
||||||
@ -1345,6 +1349,13 @@ script._getInputData = function _getInputData(s, type) {
|
|||||||
assert(typeof type === 'string');
|
assert(typeof type === 'string');
|
||||||
|
|
||||||
if (type === 'pubkey') {
|
if (type === 'pubkey') {
|
||||||
|
if (s.length < 1) {
|
||||||
|
return {
|
||||||
|
type: 'pubkey',
|
||||||
|
side: 'input',
|
||||||
|
none: true
|
||||||
|
};
|
||||||
|
}
|
||||||
sig = s[0];
|
sig = s[0];
|
||||||
return {
|
return {
|
||||||
type: 'pubkey',
|
type: 'pubkey',
|
||||||
@ -1355,6 +1366,13 @@ script._getInputData = function _getInputData(s, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'pubkeyhash') {
|
if (type === 'pubkeyhash') {
|
||||||
|
if (s.length < 2) {
|
||||||
|
return {
|
||||||
|
type: 'pubkeyhash',
|
||||||
|
side: 'input',
|
||||||
|
none: true
|
||||||
|
};
|
||||||
|
}
|
||||||
sig = s[0];
|
sig = s[0];
|
||||||
key = s[1];
|
key = s[1];
|
||||||
hash = bcoin.wallet.key2hash(key);
|
hash = bcoin.wallet.key2hash(key);
|
||||||
@ -1370,6 +1388,13 @@ script._getInputData = function _getInputData(s, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'multisig') {
|
if (type === 'multisig') {
|
||||||
|
if (s.length < 2) {
|
||||||
|
return {
|
||||||
|
type: 'multisig',
|
||||||
|
side: 'input',
|
||||||
|
none: true
|
||||||
|
};
|
||||||
|
}
|
||||||
sig = s.slice(1);
|
sig = s.slice(1);
|
||||||
return {
|
return {
|
||||||
type: 'multisig',
|
type: 'multisig',
|
||||||
@ -1381,6 +1406,13 @@ script._getInputData = function _getInputData(s, type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'scripthash') {
|
if (type === 'scripthash') {
|
||||||
|
if (s.length < 1) {
|
||||||
|
return {
|
||||||
|
type: 'scripthash',
|
||||||
|
side: 'input',
|
||||||
|
none: true
|
||||||
|
};
|
||||||
|
}
|
||||||
raw = s[s.length - 1];
|
raw = s[s.length - 1];
|
||||||
redeem = script.decode(raw);
|
redeem = script.decode(raw);
|
||||||
locktime = script.getLocktime(redeem);
|
locktime = script.getLocktime(redeem);
|
||||||
|
|||||||
@ -86,6 +86,8 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
|
|||||||
var i, input, key, unspent, index, orphan;
|
var i, input, key, unspent, index, orphan;
|
||||||
var out, key, orphans, some;
|
var out, key, orphans, some;
|
||||||
|
|
||||||
|
this._wallet.fillPrevout(tx);
|
||||||
|
|
||||||
if (strict) {
|
if (strict) {
|
||||||
if (!this._wallet.ownInput(tx) && !this._wallet.ownOutput(tx))
|
if (!this._wallet.ownInput(tx) && !this._wallet.ownOutput(tx))
|
||||||
return false;
|
return false;
|
||||||
@ -120,17 +122,14 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
|
|||||||
key = input.prevout.hash + '/' + input.prevout.index;
|
key = input.prevout.hash + '/' + input.prevout.index;
|
||||||
unspent = this._unspent[key];
|
unspent = this._unspent[key];
|
||||||
|
|
||||||
if (!input.prevout.tx && this._all[input.prevout.hash])
|
|
||||||
input.prevout.tx = this._all[input.prevout.hash];
|
|
||||||
|
|
||||||
if (unspent) {
|
if (unspent) {
|
||||||
// Add TX to inputs and spend money
|
// 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(index !== -1);
|
||||||
assert(tx.inputs[index] === input);
|
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);
|
assert(tx.inputs[index].prevout.index === unspent.index);
|
||||||
input.prevout.tx = unspent.tx;
|
input.output = unspent;
|
||||||
|
|
||||||
// Skip invalid transactions
|
// Skip invalid transactions
|
||||||
if (!tx.verify(index))
|
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,
|
// signature checking code to ownInput for p2sh and p2pk,
|
||||||
// we could in theory use ownInput here (and down below)
|
// we could in theory use ownInput here (and down below)
|
||||||
// instead.
|
// instead.
|
||||||
if (input.prevout.tx) {
|
if (input.output) {
|
||||||
if (!this._wallet.ownOutput(input.prevout.tx, input.prevout.index))
|
if (!this._wallet.ownOutput(input.output))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +176,7 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
|
|||||||
assert(index !== -1);
|
assert(index !== -1);
|
||||||
assert(orphan.tx.inputs[index].prevout.hash === tx.hash('hex'));
|
assert(orphan.tx.inputs[index].prevout.hash === tx.hash('hex'));
|
||||||
assert(orphan.tx.inputs[index].prevout.index === i);
|
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
|
// Verify that input script is correct, if not - add output to unspent
|
||||||
// and remove orphan from storage
|
// and remove orphan from storage
|
||||||
@ -211,7 +210,7 @@ TXPool.prototype.add = function add(tx, noWrite, strict) {
|
|||||||
|
|
||||||
delete this._orphans[key];
|
delete this._orphans[key];
|
||||||
if (!orphans) {
|
if (!orphans) {
|
||||||
this._unspent[key] = { tx: tx, index: i };
|
this._unspent[key] = bcoin.output.prev(tx, i);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,11 +326,11 @@ TXPool.prototype._addInput = function _addInput(tx, i, remove) {
|
|||||||
var input = tx.inputs[i];
|
var input = tx.inputs[i];
|
||||||
var prev, address;
|
var prev, address;
|
||||||
|
|
||||||
if (!this._wallet.ownOutput(input.prevout.tx, input.prevout.index))
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(input.output);
|
assert(input.output);
|
||||||
|
|
||||||
|
if (!this._wallet.ownOutput(input.output))
|
||||||
|
return;
|
||||||
|
|
||||||
prev = input.output;
|
prev = input.output;
|
||||||
address = prev.getAddress();
|
address = prev.getAddress();
|
||||||
|
|
||||||
@ -378,7 +377,7 @@ TXPool.prototype.getUnspent = function getUnspent(address) {
|
|||||||
return Object.keys(this._unspent).map(function(key) {
|
return Object.keys(this._unspent).map(function(key) {
|
||||||
return this._unspent[key];
|
return this._unspent[key];
|
||||||
}, this).filter(function(item) {
|
}, this).filter(function(item) {
|
||||||
return address.ownOutput(item.tx, item.index);
|
return address.ownOutput(item);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
113
lib/bcoin/tx.js
113
lib/bcoin/tx.js
@ -128,14 +128,11 @@ TX.prototype.input = TX.prototype.addInput;
|
|||||||
TX.prototype._addInput = function _addInput(options, index) {
|
TX.prototype._addInput = function _addInput(options, index) {
|
||||||
var input, ex, i, prevout;
|
var input, ex, i, prevout;
|
||||||
|
|
||||||
if (options instanceof TX)
|
if (options instanceof TX) {
|
||||||
options = { prevout: { tx: options, index: index } };
|
options = { tx: options, index: index };
|
||||||
else if (typeof options === 'string' || utils.isBuffer(options))
|
} else if (typeof options === 'string' || utils.isBuffer(options)) {
|
||||||
options = { prevout: { hash: options, index: index } };
|
options = { hash: options, index: index };
|
||||||
else if (!options.prevout)
|
}
|
||||||
options = { prevout: options, script: options.script, sequence: options.sequence };
|
|
||||||
else
|
|
||||||
options = options;
|
|
||||||
|
|
||||||
if (options.out)
|
if (options.out)
|
||||||
options.prevout = options.out;
|
options.prevout = options.out;
|
||||||
@ -143,16 +140,37 @@ TX.prototype._addInput = function _addInput(options, index) {
|
|||||||
if (options.seq != null)
|
if (options.seq != null)
|
||||||
options.sequence = options.seq;
|
options.sequence = options.seq;
|
||||||
|
|
||||||
if (options.prevout.tx)
|
if (!options.prevout) {
|
||||||
options.prevout.hash = options.prevout.tx.hash('hex');
|
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({
|
input = bcoin.input({
|
||||||
tx: this,
|
tx: this,
|
||||||
prevout: {
|
prevout: {
|
||||||
tx: options.prevout.tx,
|
|
||||||
hash: options.prevout.hash,
|
hash: options.prevout.hash,
|
||||||
index: options.prevout.index
|
index: options.prevout.index
|
||||||
},
|
},
|
||||||
|
output: options.output,
|
||||||
script: options.script,
|
script: options.script,
|
||||||
sequence: options.sequence
|
sequence: options.sequence
|
||||||
});
|
});
|
||||||
@ -161,8 +179,8 @@ TX.prototype._addInput = function _addInput(options, index) {
|
|||||||
i = this._inputIndex(input.prevout.hash, input.prevout.index);
|
i = this._inputIndex(input.prevout.hash, input.prevout.index);
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
ex = this.inputs[i];
|
ex = this.inputs[i];
|
||||||
input.prevout.tx = input.prevout.tx || ex.prevout.tx;
|
input.output = input.output || ex.output;
|
||||||
input.sequence = input.sequence || ex.sequence;
|
input.sequence = input.sequence != null ? input.sequence : ex.sequence;
|
||||||
input.script = input.script.length ? input.script : ex.script;
|
input.script = input.script.length ? input.script : ex.script;
|
||||||
this.inputs[i] = input;
|
this.inputs[i] = input;
|
||||||
} else {
|
} else {
|
||||||
@ -886,10 +904,6 @@ TX.prototype.verify = function verify(index, force, flags) {
|
|||||||
if (!input.output)
|
if (!input.output)
|
||||||
return false;
|
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);
|
return bcoin.script.verify(input.script, input.output.script, this, i, flags);
|
||||||
}, this);
|
}, this);
|
||||||
};
|
};
|
||||||
@ -1015,7 +1029,7 @@ TX.prototype.getInputs = function getInputs(unspent, address, fee) {
|
|||||||
|
|
||||||
// Oldest unspents first
|
// Oldest unspents first
|
||||||
unspent = unspent.slice().sort(function(a, b) {
|
unspent = unspent.slice().sort(function(a, b) {
|
||||||
return b.tx.getConfirmations() - a.tx.getConfirmations();
|
return a.height - b.height;
|
||||||
});
|
});
|
||||||
|
|
||||||
function addInput(unspent) {
|
function addInput(unspent) {
|
||||||
@ -1289,7 +1303,7 @@ TX.prototype.getTargetLocktime = function getTargetLocktime() {
|
|||||||
|
|
||||||
TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
|
TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
|
||||||
var inputs = [];
|
var inputs = [];
|
||||||
var i, input, j, addresses, scriptAddress;
|
var i, input;
|
||||||
|
|
||||||
if (typeof addressTable === 'string')
|
if (typeof addressTable === 'string')
|
||||||
addressTable = [addressTable];
|
addressTable = [addressTable];
|
||||||
@ -1313,24 +1327,10 @@ TX.prototype.testInputs = function testInputs(addressTable, index, collect) {
|
|||||||
|
|
||||||
input = this.inputs[i];
|
input = this.inputs[i];
|
||||||
|
|
||||||
addresses = input.getAddresses();
|
if (input.test(addressTable)) {
|
||||||
if (addresses) {
|
if (!collect)
|
||||||
for (j = 0; j < addresses.length; j++) {
|
return true;
|
||||||
if (addressTable[addresses[j]] != null) {
|
inputs.push(input);
|
||||||
if (!collect)
|
|
||||||
return true;
|
|
||||||
inputs.push(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptAddress = input.getScriptAddress();
|
|
||||||
if (scriptAddress) {
|
|
||||||
if (addressTable[scriptAddress] != null) {
|
|
||||||
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) {
|
TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
|
||||||
var outputs = [];
|
var outputs = [];
|
||||||
var i, output, data, j, addresses, scriptAddress;
|
var i, output;
|
||||||
|
|
||||||
if (typeof addressTable === 'string')
|
if (typeof addressTable === 'string')
|
||||||
addressTable = [addressTable];
|
addressTable = [addressTable];
|
||||||
@ -1369,24 +1369,10 @@ TX.prototype.testOutputs = function testOutputs(addressTable, index, collect) {
|
|||||||
|
|
||||||
output = this.outputs[i];
|
output = this.outputs[i];
|
||||||
|
|
||||||
addresses = output.getAddresses();
|
if (output.test(addressTable)) {
|
||||||
if (addresses) {
|
if (!collect)
|
||||||
for (j = 0; j < addresses.length; j++) {
|
return true;
|
||||||
if (addressTable[addresses[j]] != null) {
|
outputs.push(output);
|
||||||
if (!collect)
|
|
||||||
return true;
|
|
||||||
outputs.push(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptAddress = output.getScriptAddress();
|
|
||||||
if (scriptAddress) {
|
|
||||||
if (addressTable[scriptAddress] != null) {
|
|
||||||
if (!collect)
|
|
||||||
return true;
|
|
||||||
outputs.push(output);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1438,7 +1424,7 @@ TX.prototype.hasPrevout = function hasPrevout() {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
return this.inputs.every(function(input) {
|
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) {
|
inputs = this.inputs.filter(function(input) {
|
||||||
if (!input.prevout.tx && txs[input.prevout.hash])
|
if (!input.output && txs[input.prevout.hash])
|
||||||
input.prevout.tx = txs[input.prevout.hash];
|
input.output = bcoin.output.prev(txs[input.prevout.hash], input.prevout.index);
|
||||||
return !!input.prevout.tx;
|
return !!input.output;
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
return inputs.length === this.inputs.length;
|
return inputs.length === this.inputs.length;
|
||||||
@ -1646,10 +1632,10 @@ TX.prototype.getPriority = function getPriority() {
|
|||||||
for (i = 0; i < this.inputs.length; i++) {
|
for (i = 0; i < this.inputs.length; i++) {
|
||||||
input = this.inputs[i];
|
input = this.inputs[i];
|
||||||
|
|
||||||
if (!input.prevout.tx)
|
if (!input.output)
|
||||||
return constants.tx.freeThreshold.clone();
|
return constants.tx.freeThreshold.clone();
|
||||||
|
|
||||||
age = input.prevout.tx.getConfirmations();
|
age = input.output.getConfirmations();
|
||||||
|
|
||||||
if (age === -1)
|
if (age === -1)
|
||||||
age = 0;
|
age = 0;
|
||||||
@ -1749,7 +1735,8 @@ TX.prototype.inspect = function inspect() {
|
|||||||
copy.fee = utils.btc(this.getFee());
|
copy.fee = utils.btc(this.getFee());
|
||||||
copy.height = this.getHeight();
|
copy.height = this.getHeight();
|
||||||
copy.confirmations = this.getConfirmations();
|
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();
|
copy.date = new Date((copy.ts || 0) * 1000).toISOString();
|
||||||
if (copy.hardFee)
|
if (copy.hardFee)
|
||||||
copy.hardFee = utils.btc(copy.hardFee);
|
copy.hardFee = utils.btc(copy.hardFee);
|
||||||
|
|||||||
@ -813,11 +813,39 @@ Wallet.prototype.getAddress = function getAddress() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.ownInput = function ownInput(tx, index) {
|
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);
|
this.fillPrevout(tx);
|
||||||
return tx.testInputs(this._addressTable, index, true);
|
return tx.testInputs(this._addressTable, index, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.ownOutput = function ownOutput(tx, index) {
|
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);
|
return tx.testOutputs(this._addressTable, index, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -831,13 +859,11 @@ Wallet.prototype.fill = function fill(tx, address, fee) {
|
|||||||
|
|
||||||
unspent = this.getUnspent();
|
unspent = this.getUnspent();
|
||||||
|
|
||||||
items = unspent.filter(function(item) {
|
items = unspent.filter(function(coin) {
|
||||||
var output = item.tx.outputs[item.index];
|
if (bcoin.script.isScripthash(coin.script))
|
||||||
|
|
||||||
if (bcoin.script.isScripthash(output.script))
|
|
||||||
return this.type === 'scripthash';
|
return this.type === 'scripthash';
|
||||||
|
|
||||||
if (bcoin.script.isMultisig(output.script))
|
if (bcoin.script.isMultisig(coin.script))
|
||||||
return this.type === 'multisig';
|
return this.type === 'multisig';
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user