use dynamic input and output objects.

This commit is contained in:
Christopher Jeffrey 2015-12-22 04:57:35 -08:00
parent a91f245e86
commit a17fe6fe5f
4 changed files with 196 additions and 138 deletions

View File

@ -12,6 +12,8 @@ bcoin.utils = require('./bcoin/utils');
bcoin.bloom = require('./bcoin/bloom');
bcoin.protocol = require('./bcoin/protocol');
bcoin.script = require('./bcoin/script');
bcoin.input = require('./bcoin/input');
bcoin.output = require('./bcoin/output');
bcoin.tx = require('./bcoin/tx');
bcoin.txPool = require('./bcoin/tx-pool');
bcoin.block = require('./bcoin/block');

91
lib/bcoin/input.js Normal file
View File

@ -0,0 +1,91 @@
/**
* input.js - input object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* https://github.com/indutny/bcoin
*/
var bn = require('bn.js');
var bcoin = require('../bcoin');
var utils = bcoin.utils;
/**
* Input
*/
function Input(options) {
var tx = options.tx;
var lock;
if (!(this instanceof Input))
return new Input(options);
if (!tx)
throw new Error('No TX passed into Input.');
this.out = {
tx: options.out.tx || null,
hash: options.out.hash || null,
index: options.out.index
};
this.script = options.script ? options.script.slice() : [];
this.seq = options.seq === undefined ? 0xffffffff : options.seq;
if (options.script && options.script._raw)
utils.hidden(this.script, '_raw', options.script._raw);
if (this.output) {
lock = this.lock;
if (lock >= 0) {
if (tx._lock === 0)
tx.lock = Math.max(lock, tx.lock);
if (!bcoin.script.spendable(this.output.script, tx.lock))
throw new Error('Cannot spend ' + utils.revHex(this.out.hash));
}
}
if (tx.lock !== 0) {
if (options.seq === undefined)
this.seq = 0;
}
}
Input.prototype.__defineGetter__('data', function() {
return bcoin.tx.getInputData(this);
});
Input.prototype.__defineGetter__('addr', function() {
return this.data.addr;
});
Input.prototype.__defineGetter__('type', function() {
return this.data.type;
});
Input.prototype.__defineGetter__('lock', function() {
if (!this.output)
return;
return this.output.lock;
});
Input.prototype.__defineGetter__('output', function() {
if (!this.out.tx)
return;
return this.out.tx.outputs[this.out.index];
});
Input.prototype.__defineGetter__('value', function() {
if (!this.output)
return;
return this.output.value;
});
Input.prototype.__defineGetter__('tx', function() {
return this.out.tx;
});
/**
* Expose
*/
module.exports = Input;

60
lib/bcoin/output.js Normal file
View File

@ -0,0 +1,60 @@
/**
* output.js - output object for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* https://github.com/indutny/bcoin
*/
var bn = require('bn.js');
var bcoin = require('../bcoin');
var utils = bcoin.utils;
/**
* Output
*/
function Output(options) {
var tx = options.tx;
var value;
if (!(this instanceof Output))
return new Output(options);
if (!tx)
throw new Error('No TX passed into Input.');
value = options.value;
if (typeof value === 'number' && (value | 0) === value)
value = new bn(value);
this.value = utils.satoshi(value || new bn(0));
this.script = options.script ? options.script.slice() : [];
if (options.script && options.script._raw)
utils.hidden(this.script, '_raw', options.script._raw);
}
Output.prototype.__defineGetter__('data', function() {
return bcoin.tx.getOutputData(this);
});
Output.prototype.__defineGetter__('addr', function() {
return this.data.addr;
});
Output.prototype.__defineGetter__('type', function() {
return this.data.type;
});
Output.prototype.__defineGetter__('lock', function() {
var lock = bcoin.script.lockTime(this.script);
if (!lock)
return;
return lock.toNumber();
});
/**
* Expose
*/
module.exports = Output;

View File

@ -89,70 +89,51 @@ TX.prototype.input = function input(i, index) {
return this;
};
TX.prototype._input = function _input(i, index) {
var hash, input, prev, lock, index, ex;
TX.prototype._input = function _input(obj, index) {
var options, hash, input, ex, i;
if (i instanceof TX)
i = { tx: i, index: index };
else if (typeof i === 'string' || Array.isArray(i))
i = { hash: i, index: index };
if (i.tx)
hash = i.tx.hash('hex');
else if (i.out)
hash = i.out.hash;
if (obj instanceof TX)
options = { tx: obj, index: index };
else if (typeof obj === 'string' || Array.isArray(obj))
options = { hash: obj, index: index };
else
hash = i.hash;
options = obj;
if (options.tx)
hash = options.tx.hash('hex');
else if (options.out)
hash = options.out.hash;
else
hash = options.hash;
if (typeof hash !== 'string')
hash = utils.toHex(hash);
input = {
input = bcoin.input({
tx: this,
out: {
tx: (i.out ? i.out.tx : i.tx) || null,
hash: utils.toHex(hash),
index: i.out ? i.out.index : i.index
tx: options.out ? options.out.tx : options.tx,
hash: hash,
index: options.out ? options.out.index : options.index
},
script: i.script ? i.script.slice() : [],
seq: i.seq === undefined ? 0xffffffff : i.seq,
get data() {
return TX.getInputData(this);
}
};
if (i.script && i.script._raw)
utils.hidden(input.script, '_raw', i.script._raw);
if (input.out.tx) {
prev = input.out.tx.outputs[input.out.index].script;
lock = bcoin.script.lockTime(prev);
if (lock) {
if (this._lock === 0)
this.lock = Math.max(lock.toNumber(), this.lock);
if (!bcoin.script.spendable(prev, this.lock))
throw new Error('Cannot spend ' + utils.revHex(input.out.hash));
}
}
if (this.lock !== 0) {
if (i.seq === undefined)
input.seq = 0;
}
script: options.script,
seq: options.seq
});
// Try modifying existing input first
index = this._inputIndex(hash, index);
if (index !== -1) {
ex = this.inputs[index];
i = this._inputIndex(hash, index);
if (i !== -1) {
ex = this.inputs[i];
input.out.tx = input.out.tx || ex.out.tx;
input.seq = input.seq || ex.seq;
input.script = input.script.length ? input.script : ex.script;
this.inputs[index] = input;
this.inputs[i] = input;
} else {
this.inputs.push(input);
index = this.inputs.length - 1;
i = this.inputs.length - 1;
}
return index;
return i;
};
TX.prototype._inputIndex = function _inputIndex(hash, index) {
@ -170,78 +151,6 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
return -1;
};
TX.prototype.prevOut = function prevOut(i, def) {
var input;
if (typeof i === 'object')
i = this.inputs.indexOf(i);
input = this.inputs[i];
if (!input || !input.out.tx || input.out.index == null)
return def;
return input.out.tx.outputs[input.out.index] || def;
};
TX.prototype.signatureHash = function signatureHash(i, s, type) {
var input, hash;
if (s != null && !Array.isArray(s)) {
type = s;
s = null;
}
if (typeof i === 'object')
i = this.inputs.indexOf(i);
if (!type)
type = 'all';
if (typeof type === 'string')
type = constants.hashType[type];
// Get the current input.
input = this.inputs[i];
// Get the previous output's subscript
s = s || input.out.tx.getSubscript(input.out.index);
// Get the hash of the current tx, minus the other inputs, plus the sighash.
hash = this.subscriptHash(i, s, type);
return hash;
};
TX.prototype.signature = function signature(i, key, s, type) {
var hash, signature;
if (s != null && !Array.isArray(s)) {
type = s;
s = null;
}
if (typeof i === 'object')
i = this.inputs.indexOf(i);
if (!type)
type = 'all';
if (typeof type === 'string')
type = constants.hashType[type];
// Get the hash of the current tx, minus the other inputs, plus the sighash.
hash = this.signatureHash(i, s, type);
// Sign the transaction with our one input
signature = bcoin.ecdsa.sign(hash, key.priv).toDER();
// Add the sighash as a single byte to the signature
signature = signature.concat(type);
return signature;
};
// Build the scriptSigs for inputs, excluding the signatures
TX.prototype.scriptInput = function scriptInput(input, pub) {
// Get the previous output's subscript
@ -423,27 +332,26 @@ TX.prototype.scriptSig = function scriptSig(input, key, pub, type) {
return input.script;
};
TX.prototype.output = function output(options, value) {
if (options instanceof bcoin.wallet)
options = options.getAddress();
TX.prototype.output = function output(obj, value) {
var options;
if (typeof options === 'string') {
if (obj instanceof bcoin.wallet)
obj = obj.getAddress();
if (typeof obj === 'string') {
options = {
address: options,
address: obj,
value: value
};
} else {
options = obj;
}
var output = {
value: new bn(options.value),
script: options.script ? options.script.slice() : [],
get data() {
return TX.getOutputData(this);
}
};
if (options.script && options.script._raw)
utils.hidden(output.script, '_raw', options.script._raw);
var output = bcoin.output({
tx: this,
value: options.value,
script: options.script
});
this.outputs.push(output);
@ -458,13 +366,10 @@ TX.prototype.out = TX.prototype.output;
TX.prototype.scriptOutput = function scriptOutput(output, options) {
options = options || output;
var script = output.script ? output.script.slice() : [];
var script = output.script;
var keys, m, n;
var hash, color;
if (output.script && output.script._raw)
utils.hidden(script, '_raw', output.script._raw);
if (Array.isArray(options.keys || options.address)) {
// Raw multisig transaction
// https://github.com/bitcoin/bips/blob/master/bip-0010.mediawiki