diff --git a/lib/block/block.js b/lib/block/block.js index e127797..1b067b8 100644 --- a/lib/block/block.js +++ b/lib/block/block.js @@ -43,18 +43,7 @@ Block._from = function _from(arg) { } else if (JSUtil.isValidJSON(arg)) { info = Block._fromJSON(arg); } else if (_.isObject(arg)) { - info = { - /** - * @name Block#header - * @type {BlockHeader} - */ - header: arg.header, - /** - * @name Block#transactions - * @type {Transaction[]} - */ - transactions: arg.transactions - }; + info = Block._fromObject(arg); } else { throw new TypeError('Unrecognized argument for Block'); } @@ -62,27 +51,35 @@ Block._from = function _from(arg) { }; /** - * @param {String|Object} - A JSON string or object + * @param {String} - A JSON string * @returns {Object} - An object representing block data * @private */ Block._fromJSON = function _fromJSON(data) { - if (JSUtil.isValidJSON(data)) { - data = JSON.parse(data); - } + $.checkArgument(JSUtil.isValidJSON(data), 'data must be valid JSON'); + data = JSON.parse(data); + return Block._fromObject(data); +}; + +/** + * @param {Object} - A plain javascript object + * @returns {Object} - An object representing block data + * @private + */ +Block._fromObject = function _fromObject(data) { var transactions = []; data.transactions.forEach(function(data) { transactions.push(Transaction().fromJSON(data)); }); var info = { - header: BlockHeader.fromJSON(data.header), + header: BlockHeader.fromObject(data.header), transactions: transactions }; return info; }; /** - * @param {String|Object} - A JSON string or object + * @param {String} - A JSON string * @returns {Block} - An instance of block */ Block.fromJSON = function fromJSON(json) { @@ -90,6 +87,15 @@ Block.fromJSON = function fromJSON(json) { return new Block(info); }; +/** + * @param {Object} - A plain javascript object + * @returns {Block} - An instance of block + */ +Block.fromObject = function fromObject(obj) { + var info = Block._fromObject(obj); + return new Block(info); +}; + /** * @param {BufferReader} - Block data * @returns {Object} - An object representing the block data diff --git a/lib/block/blockheader.js b/lib/block/blockheader.js index 01f2e81..c3280e3 100644 --- a/lib/block/blockheader.js +++ b/lib/block/blockheader.js @@ -7,6 +7,7 @@ var BufferReader = require('../encoding/bufferreader'); var BufferWriter = require('../encoding/bufferwriter'); var Hash = require('../crypto/hash'); var JSUtil = require('../util/js'); +var $ = require('../util/preconditions'); /** * Instantiate a BlockHeader from a Buffer, JSON object, or Object with @@ -37,14 +38,7 @@ BlockHeader._from = function _from(arg) { } else if (JSUtil.isValidJSON(arg)) { info = BlockHeader._fromJSON(arg); } else if (_.isObject(arg)) { - info = { - version: arg.version, - prevHash: arg.prevHash, - merkleRoot: arg.merkleRoot, - time: arg.time, - bits: arg.bits, - nonce: arg.nonce - }; + info = BlockHeader._fromObject(arg); } else { throw new TypeError('Unrecognized argument for BlockHeader'); } @@ -52,18 +46,35 @@ BlockHeader._from = function _from(arg) { }; /** - * @param {String|Object} - A JSON string or object + * @param {String} - A JSON string * @returns {Object} - An object representing block header data * @private */ BlockHeader._fromJSON = function _fromJSON(data) { - if (JSUtil.isValidJSON(data)) { - data = JSON.parse(data); + $.checkArgument(JSUtil.isValidJSON(data), 'data must be a valid JSON string'); + data = JSON.parse(data); + return BlockHeader._fromObject(data); +}; + +/** + * @param {Object} - A JSON string + * @returns {Object} - An object representing block header data + * @private + */ +BlockHeader._fromObject = function _fromObject(data) { + $.checkArgument(data, 'data is required'); + var prevHash = data.prevHash; + var merkleRoot = data.merkleRoot; + if (_.isString(data.prevHash)) { + prevHash = BufferUtil.reverse(new Buffer(data.prevHash, 'hex')); + } + if (_.isString(data.merkleRoot)) { + merkleRoot = BufferUtil.reverse(new Buffer(data.merkleRoot, 'hex')); } var info = { version: data.version, - prevHash: new Buffer(data.prevHash, 'hex'), - merkleRoot: new Buffer(data.merkleRoot, 'hex'), + prevHash: prevHash, + merkleRoot: merkleRoot, time: data.time, timestamp: data.time, bits: data.bits, @@ -73,7 +84,7 @@ BlockHeader._fromJSON = function _fromJSON(data) { }; /** - * @param {String|Object} - A JSON string or object + * @param {String} - A JSON string or object * @returns {BlockHeader} - An instance of block header */ BlockHeader.fromJSON = function fromJSON(json) { @@ -81,6 +92,15 @@ BlockHeader.fromJSON = function fromJSON(json) { return new BlockHeader(info); }; +/** + * @param {Object} - A plain javascript object + * @returns {BlockHeader} - An instance of block header + */ +BlockHeader.fromObject = function fromObject(obj) { + var info = BlockHeader._fromObject(obj); + return new BlockHeader(info); +}; + /** * @param {Binary} - Raw block binary data or buffer * @returns {BlockHeader} - An instance of block header @@ -144,8 +164,8 @@ BlockHeader.fromBufferReader = function fromBufferReader(br) { BlockHeader.prototype.toObject = function toObject() { return { version: this.version, - prevHash: this.prevHash.toString('hex'), - merkleRoot: this.merkleRoot.toString('hex'), + prevHash: BufferUtil.reverse(this.prevHash).toString('hex'), + merkleRoot: BufferUtil.reverse(this.merkleRoot).toString('hex'), time: this.time, bits: this.bits, nonce: this.nonce @@ -216,8 +236,8 @@ var idProperty = { writeable: false, enumerable: true, /** - * @returns {string} - The big endian hash buffer of the header - */ + * @returns {string} - The big endian hash buffer of the header + */ get: function() { if (!this._id) { this._id = BufferReader(this._getHash()).readReverse().toString('hex'); diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 09ccc1a..3b6a7f4 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -313,6 +313,7 @@ Transaction.prototype.toObject = function toObject() { obj.changeIndex = this._changeIndex; } if (!_.isUndefined(this._fee)) { + console.log(this._fee); obj.fee = this._fee; } return obj; @@ -320,6 +321,9 @@ Transaction.prototype.toObject = function toObject() { Transaction.prototype.fromObject = function(transaction) { var self = this; + if (transaction instanceof Transaction) { + transaction = transaction.toObject(); + } _.each(transaction.inputs, function(input) { if (!input.output || !input.output.script) { self.uncheckedAddInput(new Input(input)); @@ -595,6 +599,7 @@ Transaction.prototype.hasAllUtxoInfo = function() { * @return {Transaction} this, for chaining */ Transaction.prototype.fee = function(amount) { + $.checkArgument(_.isNumber(amount), 'amount must be a number'); this._fee = amount; this._updateChangeOutput(); return this; diff --git a/test/block.js b/test/block.js index f6f0685..cdf1758 100644 --- a/test/block.js +++ b/test/block.js @@ -167,7 +167,7 @@ describe('Block', function() { }); - describe.only('#toObject', function() { + describe('#toObject', function() { it('should recover a block from genesis block buffer', function() { var block = Block.fromBuffer(blockOneBuf); @@ -199,6 +199,13 @@ describe('Block', function() { }); }); + it('roundtrips correctly', function() { + var block = Block.fromBuffer(blockOneBuf); + var obj = block.toObject(); + var block2 = Block.fromObject(obj); + block2.toObject().should.deep.equal(block.toObject()); + }); + }); describe('#_getHash', function() {