369 lines
8.2 KiB
JavaScript
369 lines
8.2 KiB
JavaScript
/**
|
|
* 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;
|
|
var assert = utils.assert;
|
|
var constants = bcoin.protocol.constants;
|
|
|
|
/**
|
|
* Input
|
|
*/
|
|
|
|
function Input(options) {
|
|
var prevout;
|
|
|
|
if (!(this instanceof Input))
|
|
return new Input(options);
|
|
|
|
prevout = options.prevout || options.out;
|
|
|
|
this.prevout = {
|
|
hash: prevout.hash,
|
|
index: prevout.index,
|
|
rhash: prevout.rhash
|
|
};
|
|
|
|
if (options.output)
|
|
this.output = bcoin.coin(options.output);
|
|
|
|
if (utils.isBuffer(this.prevout.hash))
|
|
this.prevout.hash = utils.toHex(this.prevout.hash);
|
|
|
|
if (!this.prevout.rhash)
|
|
this.prevout.rhash = utils.revHex(this.prevout.hash);
|
|
|
|
this.script = options.script ? options.script.slice() : [];
|
|
this.sequence = options.sequence == null ? 0xffffffff : options.sequence;
|
|
this._size = options._size || 0;
|
|
this._offset = options._offset || 0;
|
|
|
|
// Legacy
|
|
if (options.seq != null)
|
|
this.sequence = options.seq;
|
|
|
|
if (options.script && options.script._raw)
|
|
utils.hidden(this.script, '_raw', options.script._raw);
|
|
}
|
|
|
|
// Legacy
|
|
Input.prototype.__defineSetter__('seq', function(sequence) {
|
|
return this.sequence = sequence;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('seq', function() {
|
|
return this.sequence;
|
|
});
|
|
|
|
Input.prototype.__defineSetter__('out', function(prevout) {
|
|
return this.prevout = prevout;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('out', function() {
|
|
return this.prevout;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('data', function() {
|
|
var data;
|
|
|
|
if (this._data)
|
|
return this._data;
|
|
|
|
data = Input.getData(this);
|
|
|
|
if (this.script.length && this.output)
|
|
utils.hidden(this, '_data', data);
|
|
|
|
return data;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('type', function() {
|
|
return this.data.type;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('subtype', function() {
|
|
return this.data.subtype;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('signature', function() {
|
|
return this.signatures[0];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('key', function() {
|
|
return this.keys[0];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('hash160', function() {
|
|
return this.data.scriptHash || this.hashes[0];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('id', function() {
|
|
return this.address || this.getID();
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('address', function() {
|
|
return this.data.address;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('signatures', function() {
|
|
return this.data.signatures || [];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('keys', function() {
|
|
return this.data.keys || [];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('hashes', function() {
|
|
return this.data.hashes || [];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('addresses', function() {
|
|
return this.data.addresses || [];
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('redeem', function() {
|
|
return this.data.redeem;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('scriptHash', function() {
|
|
return this.data.scriptHash;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('scriptAddress', function() {
|
|
return this.data.scriptAddress;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('m', function() {
|
|
return this.data.m || 1;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('n', function() {
|
|
return this.data.n || this.m;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('locktime', function() {
|
|
if (!this.output)
|
|
return 0;
|
|
return this.output.locktime;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('flags', function() {
|
|
return this.data.flags;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('text', function() {
|
|
return this.data.text;
|
|
});
|
|
|
|
Input.prototype.__defineGetter__('value', function() {
|
|
if (!this.output)
|
|
return;
|
|
return this.output.value;
|
|
});
|
|
|
|
// Schema and defaults for data object:
|
|
// {
|
|
// type: String,
|
|
// subtype: String,
|
|
// side: 'input',
|
|
// signatures: Array,
|
|
// keys: Array,
|
|
// hashes: Array,
|
|
// addresses: Array,
|
|
// redeem: Array,
|
|
// scriptHash: Array,
|
|
// scriptAddress: String,
|
|
// m: Number,
|
|
// n: Number,
|
|
// height: Number,
|
|
// flags: Array,
|
|
// text: String,
|
|
// locktime: Number,
|
|
// value: bn,
|
|
// script: Array,
|
|
// seq: Number,
|
|
// prev: String,
|
|
// index: Number,
|
|
// none: Boolean
|
|
// }
|
|
|
|
Input.getData = function getData(input) {
|
|
var def, data;
|
|
|
|
assert(input instanceof Input);
|
|
|
|
def = {
|
|
side: 'input',
|
|
value: new bn(0),
|
|
script: input.script,
|
|
seq: input.seq
|
|
};
|
|
|
|
def.prev = input.prevout.hash;
|
|
def.index = input.prevout.index;
|
|
|
|
if (input.isCoinbase()) {
|
|
data = bcoin.script.getCoinbaseData(input.script);
|
|
return utils.merge(def, data, {
|
|
type: 'coinbase',
|
|
none: true
|
|
});
|
|
}
|
|
|
|
if (input.output) {
|
|
data = bcoin.script.getInputData(input.script, input.output.script);
|
|
data.value = input.output.value;
|
|
return utils.merge(def, data);
|
|
}
|
|
|
|
return utils.merge(def, bcoin.script.getInputData(input.script));
|
|
};
|
|
|
|
Input.prototype.getData = function getData() {
|
|
return Input.getData(this);
|
|
};
|
|
|
|
Input.prototype.getType = function getType() {
|
|
var prev = this.output ? this.output.script : null;
|
|
return bcoin.script.getInputType(this.script, prev);
|
|
};
|
|
|
|
Input.prototype.getAddress = function getAddress() {
|
|
var prev = this.output ? this.output.script : null;
|
|
return bcoin.script.getInputAddress(this.script, prev);
|
|
};
|
|
|
|
Input.prototype.isRBF = function isRBF() {
|
|
return this.sequence === 0xffffffff - 1;
|
|
};
|
|
|
|
Input.prototype.isFinal = function isFinal() {
|
|
return this.sequence === 0xffffffff;
|
|
};
|
|
|
|
Input.prototype.getID = function getID() {
|
|
var data = bcoin.script.encode(this.script);
|
|
var hash = utils.toHex(utils.ripesha(data));
|
|
return '[' + this.type + ':' + hash.slice(0, 7) + ']';
|
|
};
|
|
|
|
Input.prototype.getLocktime = function getLocktime() {
|
|
var output, redeem, lock, type;
|
|
|
|
assert(this.output);
|
|
|
|
output = this.output;
|
|
redeem = output.script;
|
|
|
|
if (bcoin.script.isScripthash(redeem))
|
|
redeem = bcoin.script.getRedeem(this.script);
|
|
|
|
if (redeem[1] !== 'checklocktimeverify')
|
|
return;
|
|
|
|
return bcoin.script.getLocktime(redeem);
|
|
};
|
|
|
|
Input.prototype.isCoinbase = function isCoinbase() {
|
|
return +this.prevout.hash === 0;
|
|
};
|
|
|
|
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 address = this.getAddress();
|
|
|
|
if (!address)
|
|
return false;
|
|
|
|
if (typeof addressTable === 'string')
|
|
addressTable = [addressTable];
|
|
|
|
if (Array.isArray(addressTable)) {
|
|
addressTable = addressTable.reduce(function(out, address) {
|
|
out[address] = true;
|
|
return out;
|
|
}, {});
|
|
}
|
|
|
|
if (addressTable[address] != null)
|
|
return true;
|
|
|
|
return false;
|
|
};
|
|
|
|
Input.prototype.getSigops = function getSigops(scriptHash, accurate) {
|
|
var n = bcoin.script.getSigops(this.script, accurate);
|
|
if (scriptHash && !this.isCoinbase())
|
|
n += bcoin.script.getScripthashSigops(this.script);
|
|
return n;
|
|
};
|
|
|
|
Input.prototype.inspect = function inspect() {
|
|
var output = this.output
|
|
? this.output.inspect()
|
|
: { type: 'unknown', value: '0.0' };
|
|
|
|
output.hash = this.prevout.hash;
|
|
output.rhash = this.prevout.rhash;
|
|
output.index = this.prevout.index;
|
|
|
|
return {
|
|
type: this.type,
|
|
subtype: this.subtype,
|
|
address: this.address,
|
|
keys: this.keys.map(utils.toHex),
|
|
hashes: this.hashes.map(utils.toHex),
|
|
addresses: this.addresses,
|
|
scriptAddress: this.scriptAddress,
|
|
signatures: this.signatures.map(utils.toHex),
|
|
text: this.text,
|
|
locktime: this.locktime,
|
|
value: utils.btc(output.value),
|
|
script: bcoin.script.format(this.script),
|
|
redeem: this.redeem ? bcoin.script.format(this.redeem) : null,
|
|
seq: this.seq,
|
|
output: output
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Expose
|
|
*/
|
|
|
|
module.exports = Input;
|