fcoin/lib/primitives/txmeta.js
2017-02-03 22:47:26 -08:00

306 lines
6.0 KiB
JavaScript

/*!
* txmeta.js - extended transaction object for bcoin
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var util = require('../utils/util');
var TX = require('./tx');
var StaticWriter = require('../utils/staticwriter');
var BufferReader = require('../utils/reader');
/**
* An extended transaction object.
* @alias module:primitives.TXMeta
* @constructor
* @param {Object} options
*/
function TXMeta(options) {
if (!(this instanceof TXMeta))
return new TXMeta(options);
this.tx = new TX();
this.ps = util.now();
this.height = -1;
this.block = null;
this.ts = 0;
this.index = 0;
if (options)
this.fromOptions(options);
}
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
TXMeta.prototype.fromOptions = function fromOptions(options) {
if (options.tx) {
assert(options.tx instanceof TX);
this.tx = options.tx;
}
if (options.ps != null) {
assert(util.isNumber(options.ps));
this.ps = options.ps;
}
if (options.height != null) {
assert(util.isNumber(options.height));
this.height = options.height;
}
if (options.block !== undefined) {
assert(options.block === null || typeof options.block === 'string');
this.block = options.block;
}
if (options.ts != null) {
assert(util.isNumber(options.ts));
this.ts = options.ts;
}
if (options.index != null) {
assert(util.isNumber(options.index));
this.index = options.index;
}
return this;
};
/**
* Instantiate TXMeta from options.
* @param {Object} options
* @returns {TXMeta}
*/
TXMeta.fromOptions = function fromOptions(options) {
return new TXMeta().fromOptions(options);
};
/**
* Inject properties from options object.
* @private
* @param {Object} options
*/
TXMeta.prototype.fromTX = function fromTX(tx, entry, index) {
this.tx = tx;
if (entry) {
this.height = entry.height;
this.block = entry.hash;
this.ts = entry.ts;
this.index = index;
}
return this;
};
/**
* Instantiate TXMeta from options.
* @param {Object} options
* @returns {TXMeta}
*/
TXMeta.fromTX = function fromTX(tx, entry, index) {
return new TXMeta().fromTX(tx, entry, index);
};
/**
* Inspect the transaction.
* @returns {Object}
*/
TXMeta.prototype.inspect = function inspect() {
return this.format();
};
/**
* Inspect the transaction.
* @returns {Object}
*/
TXMeta.prototype.format = function format(view) {
var data = this.tx.format(view, null, this.index);
data.ps = this.ps;
data.height = this.height;
data.block = this.block ? util.revHex(this.block) : null;
data.ts = this.ts;
return data;
};
/**
* Convert transaction to JSON.
* @returns {Object}
*/
TXMeta.prototype.toJSON = function toJSON() {
return this.getJSON();
};
/**
* Convert the transaction to an object suitable
* for JSON serialization.
* @param {Network} network
* @param {CoinView} view
* @returns {Object}
*/
TXMeta.prototype.getJSON = function getJSON(network, view) {
var json = this.tx.getJSON(network, view, null, this.index);
json.ps = this.ps;
json.height = this.height;
json.block = this.block ? util.revHex(this.block) : null;
json.ts = this.ts;
return json;
};
/**
* Inject properties from a json object.
* @private
* @param {Object} json
*/
TXMeta.prototype.fromJSON = function fromJSON(json) {
this.tx.fromJSON(json);
assert(util.isNumber(json.ps));
assert(util.isNumber(json.height));
assert(!json.block || typeof json.block === 'string');
assert(util.isNumber(json.ts));
assert(util.isNumber(json.index));
this.ps = json.ps;
this.height = json.height;
this.block = util.revHex(json.block);
this.index = json.index;
return this;
};
/**
* Instantiate a transaction from a
* jsonified transaction object.
* @param {Object} json - The jsonified transaction object.
* @returns {TX}
*/
TXMeta.fromJSON = function fromJSON(json) {
return new TXMeta().fromJSON(JSON);
};
/**
* Calculate serialization size.
* @returns {Number}
*/
TXMeta.prototype.getSize = function getSize() {
var size = 0;
size += this.tx.getSize();
size += 4;
if (this.block) {
size += 1;
size += 32;
size += 4 * 3;
} else {
size += 1;
}
return size;
};
/**
* Serialize a transaction to "extended format".
* This is the serialization format bcoin uses internally
* to store transactions in the database. The extended
* serialization includes the height, block hash, index,
* timestamp, and pending-since time.
* @returns {Buffer}
*/
TXMeta.prototype.toRaw = function toRaw() {
var size = this.getSize();
var bw = new StaticWriter(size);
this.tx.toWriter(bw);
bw.writeU32(this.ps);
if (this.block) {
bw.writeU8(1);
bw.writeHash(this.block);
bw.writeU32(this.height);
bw.writeU32(this.ts);
bw.writeU32(this.index);
} else {
bw.writeU8(0);
}
return bw.render();
};
/**
* Inject properties from "extended" serialization format.
* @private
* @param {Buffer} data
*/
TXMeta.prototype.fromRaw = function fromRaw(data) {
var br = new BufferReader(data);
this.tx.fromReader(br);
this.ps = br.readU32();
if (br.readU8() === 1) {
this.block = br.readHash('hex');
this.height = br.readU32();
this.ts = br.readU32();
this.index = br.readU32();
if (this.index === 0x7fffffff)
this.index = -1;
}
return this;
};
/**
* Instantiate a transaction from a Buffer
* in "extended" serialization format.
* @param {Buffer} data
* @param {String?} enc - One of `"hex"` or `null`.
* @returns {TX}
*/
TXMeta.fromRaw = function fromRaw(data, enc) {
if (typeof data === 'string')
data = new Buffer(data, enc);
return new TXMeta().fromRaw(data);
};
/**
* Test whether an object is an TXMeta.
* @param {Object} obj
* @returns {Boolean}
*/
TXMeta.isTXMeta = function isTXMeta(obj) {
return obj
&& Array.isArray(obj.inputs)
&& typeof obj.locktime === 'number'
&& typeof obj.ps === 'number';
};
/*
* Expose
*/
module.exports = TXMeta;