use dynamic input and output objects.
This commit is contained in:
parent
a91f245e86
commit
a17fe6fe5f
@ -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
91
lib/bcoin/input.js
Normal 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
60
lib/bcoin/output.js
Normal 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;
|
||||
181
lib/bcoin/tx.js
181
lib/bcoin/tx.js
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user