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.bloom = require('./bcoin/bloom');
|
||||||
bcoin.protocol = require('./bcoin/protocol');
|
bcoin.protocol = require('./bcoin/protocol');
|
||||||
bcoin.script = require('./bcoin/script');
|
bcoin.script = require('./bcoin/script');
|
||||||
|
bcoin.input = require('./bcoin/input');
|
||||||
|
bcoin.output = require('./bcoin/output');
|
||||||
bcoin.tx = require('./bcoin/tx');
|
bcoin.tx = require('./bcoin/tx');
|
||||||
bcoin.txPool = require('./bcoin/tx-pool');
|
bcoin.txPool = require('./bcoin/tx-pool');
|
||||||
bcoin.block = require('./bcoin/block');
|
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;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
TX.prototype._input = function _input(i, index) {
|
TX.prototype._input = function _input(obj, index) {
|
||||||
var hash, input, prev, lock, index, ex;
|
var options, hash, input, ex, i;
|
||||||
|
|
||||||
if (i instanceof TX)
|
if (obj instanceof TX)
|
||||||
i = { tx: i, index: index };
|
options = { tx: obj, index: index };
|
||||||
else if (typeof i === 'string' || Array.isArray(i))
|
else if (typeof obj === 'string' || Array.isArray(obj))
|
||||||
i = { hash: i, index: index };
|
options = { hash: obj, index: index };
|
||||||
|
|
||||||
if (i.tx)
|
|
||||||
hash = i.tx.hash('hex');
|
|
||||||
else if (i.out)
|
|
||||||
hash = i.out.hash;
|
|
||||||
else
|
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')
|
if (typeof hash !== 'string')
|
||||||
hash = utils.toHex(hash);
|
hash = utils.toHex(hash);
|
||||||
|
|
||||||
input = {
|
input = bcoin.input({
|
||||||
|
tx: this,
|
||||||
out: {
|
out: {
|
||||||
tx: (i.out ? i.out.tx : i.tx) || null,
|
tx: options.out ? options.out.tx : options.tx,
|
||||||
hash: utils.toHex(hash),
|
hash: hash,
|
||||||
index: i.out ? i.out.index : i.index
|
index: options.out ? options.out.index : options.index
|
||||||
},
|
},
|
||||||
script: i.script ? i.script.slice() : [],
|
script: options.script,
|
||||||
seq: i.seq === undefined ? 0xffffffff : i.seq,
|
seq: options.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try modifying existing input first
|
// Try modifying existing input first
|
||||||
index = this._inputIndex(hash, index);
|
i = this._inputIndex(hash, index);
|
||||||
if (index !== -1) {
|
if (i !== -1) {
|
||||||
ex = this.inputs[index];
|
ex = this.inputs[i];
|
||||||
input.out.tx = input.out.tx || ex.out.tx;
|
input.out.tx = input.out.tx || ex.out.tx;
|
||||||
input.seq = input.seq || ex.seq;
|
input.seq = input.seq || ex.seq;
|
||||||
input.script = input.script.length ? input.script : ex.script;
|
input.script = input.script.length ? input.script : ex.script;
|
||||||
this.inputs[index] = input;
|
this.inputs[i] = input;
|
||||||
} else {
|
} else {
|
||||||
this.inputs.push(input);
|
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) {
|
TX.prototype._inputIndex = function _inputIndex(hash, index) {
|
||||||
@ -170,78 +151,6 @@ TX.prototype._inputIndex = function _inputIndex(hash, index) {
|
|||||||
return -1;
|
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
|
// Build the scriptSigs for inputs, excluding the signatures
|
||||||
TX.prototype.scriptInput = function scriptInput(input, pub) {
|
TX.prototype.scriptInput = function scriptInput(input, pub) {
|
||||||
// Get the previous output's subscript
|
// Get the previous output's subscript
|
||||||
@ -423,27 +332,26 @@ TX.prototype.scriptSig = function scriptSig(input, key, pub, type) {
|
|||||||
return input.script;
|
return input.script;
|
||||||
};
|
};
|
||||||
|
|
||||||
TX.prototype.output = function output(options, value) {
|
TX.prototype.output = function output(obj, value) {
|
||||||
if (options instanceof bcoin.wallet)
|
var options;
|
||||||
options = options.getAddress();
|
|
||||||
|
|
||||||
if (typeof options === 'string') {
|
if (obj instanceof bcoin.wallet)
|
||||||
|
obj = obj.getAddress();
|
||||||
|
|
||||||
|
if (typeof obj === 'string') {
|
||||||
options = {
|
options = {
|
||||||
address: options,
|
address: obj,
|
||||||
value: value
|
value: value
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
options = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
var output = {
|
var output = bcoin.output({
|
||||||
value: new bn(options.value),
|
tx: this,
|
||||||
script: options.script ? options.script.slice() : [],
|
value: options.value,
|
||||||
get data() {
|
script: options.script
|
||||||
return TX.getOutputData(this);
|
});
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.script && options.script._raw)
|
|
||||||
utils.hidden(output.script, '_raw', options.script._raw);
|
|
||||||
|
|
||||||
this.outputs.push(output);
|
this.outputs.push(output);
|
||||||
|
|
||||||
@ -458,13 +366,10 @@ TX.prototype.out = TX.prototype.output;
|
|||||||
TX.prototype.scriptOutput = function scriptOutput(output, options) {
|
TX.prototype.scriptOutput = function scriptOutput(output, options) {
|
||||||
options = options || output;
|
options = options || output;
|
||||||
|
|
||||||
var script = output.script ? output.script.slice() : [];
|
var script = output.script;
|
||||||
var keys, m, n;
|
var keys, m, n;
|
||||||
var hash, color;
|
var hash, color;
|
||||||
|
|
||||||
if (output.script && output.script._raw)
|
|
||||||
utils.hidden(script, '_raw', output.script._raw);
|
|
||||||
|
|
||||||
if (Array.isArray(options.keys || options.address)) {
|
if (Array.isArray(options.keys || options.address)) {
|
||||||
// Raw multisig transaction
|
// Raw multisig transaction
|
||||||
// https://github.com/bitcoin/bips/blob/master/bip-0010.mediawiki
|
// https://github.com/bitcoin/bips/blob/master/bip-0010.mediawiki
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user