fcoin/lib/bcoin/output.js
2016-02-06 04:54:38 -08:00

403 lines
8.7 KiB
JavaScript

/**
* 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 inherits = require('inherits');
var utils = bcoin.utils;
var assert = utils.assert;
var constants = bcoin.protocol.constants;
/**
* Output
*/
function Output(options) {
var value;
if (!(this instanceof Output))
return new Output(options);
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() : [];
// For safety: do not allow usage of
// Numbers, do not allow negative values.
assert(typeof value !== 'number');
assert(!this.value.isNeg())
assert(this.value.bitLength() <= 63);
assert(!(this.value.toArray('be', 8)[0] & 0x80));
if (options.script && options.script._raw)
utils.hidden(this.script, '_raw', options.script._raw);
}
Output.prototype.__defineGetter__('data', function() {
var data;
if (this._data)
return this._data;
data = Output.getData(this);
if (this.script.length)
utils.hidden(this, '_data', data);
return data;
});
Output.prototype.__defineGetter__('type', function() {
return this.data.type;
});
Output.prototype.__defineGetter__('signature', function() {
return this.signatures[0];
});
Output.prototype.__defineGetter__('key', function() {
return this.keys[0];
});
Output.prototype.__defineGetter__('hash160', function() {
return this.data.scriptHash || this.hashes[0];
});
Output.prototype.__defineGetter__('id', function() {
return this.address || this.getID();
});
Output.prototype.__defineGetter__('address', function() {
return this.data.scriptAddress || this.addresses[0];
});
Output.prototype.__defineGetter__('signatures', function() {
return this.data.signatures || [];
});
Output.prototype.__defineGetter__('keys', function() {
return this.data.keys || [];
});
Output.prototype.__defineGetter__('hashes', function() {
return this.data.hashes || [];
});
Output.prototype.__defineGetter__('addresses', function() {
return this.data.addresses || [];
});
Output.prototype.__defineGetter__('scriptHash', function() {
return this.data.scriptHash;
});
Output.prototype.__defineGetter__('scriptAddress', function() {
return this.data.scriptAddress;
});
Output.prototype.__defineGetter__('m', function() {
return this.data.m || 1;
});
Output.prototype.__defineGetter__('n', function() {
return this.data.n || this.m;
});
Output.prototype.__defineGetter__('locktime', function() {
return bcoin.script.getLocktime(this.script);
});
Output.prototype.__defineGetter__('flags', function() {
return this.data.flags;
});
Output.prototype.__defineGetter__('text', function() {
return this.data.text;
});
// Legacy
Output.prototype.__defineGetter__('addr', function() {
return this.address;
});
Output.prototype.__defineGetter__('addrs', function() {
return this.addresses;
});
Output.prototype.__defineGetter__('pub', function() {
return this.key;
});
Output.prototype.__defineGetter__('pubs', function() {
return this.keys;
});
Output.prototype.__defineGetter__('sig', function() {
return this.signature;
});
Output.prototype.__defineGetter__('sigs', function() {
return this.signatures;
});
Output.prototype.__defineGetter__('scriptaddr', function() {
return this.scriptAddress;
});
// Schema and defaults for data object:
// {
// type: String,
// subtype: String,
// side: 'output',
// 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
// }
Output.getData = function getData(output) {
var def;
assert(output instanceof Output);
def = {
side: 'output',
value: output.value,
script: output.script
};
return utils.merge(def, bcoin.script.getOutputData(output.script));
};
Output.prototype.getData = function getData() {
return Output.getData(this);
};
Output.prototype.getAddresses = function getAddresses() {
return this.getData().addresses;
};
Output.prototype.getScriptAddress = function getScriptAddress() {
return this.getData().scriptAddress;
};
Output.prototype.getKeyAddress = function getKeyAddress() {
return this.getData().addresses[0];
};
Output.prototype.getAddress = function getAddress() {
var data = this.getData();
if (data.scriptAddress)
return data.scriptAddress;
return data.addresses[0];
};
Output.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) + ']';
};
Output.prototype.testScript = function testScript(key, hash, keys, scriptHash, type) {
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) {
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) {
return bcoin.script.getSigops(this.script, accurate);
};
Output.prototype.inspect = function inspect() {
return {
type: this.type,
address: this.address,
keys: this.keys.map(utils.toHex),
hashes: this.hashes.map(utils.toHex),
addresses: this.addresses,
scriptAddress: this.scriptAddress,
m: this.m,
n: this.n,
text: this.text,
locktime: this.locktime,
value: utils.btc(this.value),
script: bcoin.script.format(this.script)
};
};
// 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
*/
exports = Output;
exports.prev = Prevout;
module.exports = exports;