diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ebcc68bc..5e6d15bc3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,6 +105,19 @@ DON'T: var bufferUtil = require('./util/buffer'); ``` +### G7 - General: Standard Methods + +When possible, bitcore objects should have standard methods on an instance prototype: +* `toObject` - A plain JavaScript object that can be JSON stringified +* `toJSON` - A JSON stringified object of the instance +* `toString` - A string representation of the instance +* `toBuffer` - A hex Buffer + +These should have a matching static method that can be used for instantiation: +* `fromJSON` - Should handle both JSON from `toJSON` and plain JavaScript object from `toObject` +* `fromString` - Should be able to instantiate with output from `toString` +* `fromBuffer` - Should likewise be able to instantiate from output from `toBuffer` + ### E1 - Errors: Use bitcore.Errors We've designed a structure for Errors to follow and are slowly migrating to it. @@ -233,7 +246,7 @@ the change the branch introduces. Some examples for such branches are: ```sh git checkout -b test/some-module git checkout -b feature/some-new-stuff -git checkout -b fix/some-bug +git checkout -b fix/some-bug git checkout -b remove/some-file ``` @@ -244,7 +257,7 @@ git pull --rebase bitpay master ``` Note that we require rebasing your branch instead of mergeing it, for commit -readability reasons. +readability reasons. After that, you can push the changes to your fork, by doing: ```sh diff --git a/lib/address.js b/lib/address.js index e56c429df..248b5cb9d 100644 --- a/lib/address.js +++ b/lib/address.js @@ -1,5 +1,6 @@ 'use strict'; +var $ = require('./util/preconditions'); var base58check = require('./encoding/base58check'); var Networks = require('./networks'); var Hash = require('./crypto/hash'); @@ -316,6 +317,10 @@ Address.fromJSON = function fromJSON(json) { if (JSUtil.isValidJSON(json)) { json = JSON.parse(json); } + $.checkState( + JSUtil.isHexa(json.hash), + 'Unexpected hash property, "' + json.hash + '", expected to be hex.' + ); var hashBuffer = new Buffer(json.hash, 'hex'); return new Address(hashBuffer, json.network, json.type); }; @@ -390,7 +395,7 @@ Address.prototype.toBuffer = function() { /** * @returns {Object} An object of the address */ -Address.prototype.toJSON = function toJSON() { +Address.prototype.toObject = function toObject() { return { hash: this.hashBuffer.toString('hex'), type: this.type, @@ -398,6 +403,13 @@ Address.prototype.toJSON = function toJSON() { }; }; +/** + * @returns {Object} An object of the address + */ +Address.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + /** * Will return a the string representation of the address * diff --git a/lib/block.js b/lib/block.js index 626672729..43e90c8db 100644 --- a/lib/block.js +++ b/lib/block.js @@ -70,7 +70,7 @@ Block._fromJSON = function _fromJSON(data) { magicnum: data.magicnum, blocksize: data.blocksize, blockheader: BlockHeader.fromJSON(data.blockheader), - txsvi: Varint().fromJSON(data.txsvi), + txsvi: Varint().fromString(data.txsvi), txs: txs }; return info; @@ -144,9 +144,9 @@ Block.fromRawBlock = function fromRawBlock(data) { }; /** - * @returns {Object} - A JSON object with the block properties + * @returns {Object} - A plain object with the block properties */ -Block.prototype.toJSON = function toJSON() { +Block.prototype.toObject = function toObject() { var txs = []; this.txs.forEach(function(tx) { txs.push(tx.toJSON()); @@ -154,12 +154,19 @@ Block.prototype.toJSON = function toJSON() { return { magicnum: this.magicnum, blocksize: this.blocksize, - blockheader: this.blockheader.toJSON(), - txsvi: this.txsvi.toJSON(), + blockheader: this.blockheader.toObject(), + txsvi: this.txsvi.toString(), txs: txs }; }; +/** + * @returns {String} - A JSON string + */ +Block.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + /** * @returns {Buffer} - A buffer of the block */ diff --git a/lib/blockheader.js b/lib/blockheader.js index 9300e2e92..2fdf9b464 100644 --- a/lib/blockheader.js +++ b/lib/blockheader.js @@ -139,9 +139,9 @@ BlockHeader.fromBufferReader = function fromBufferReader(br) { }; /** - * @returns {Object} - A JSON object of the BlockHeader + * @returns {Object} - A plain object of the BlockHeader */ -BlockHeader.prototype.toJSON = function toJSON() { +BlockHeader.prototype.toObject = function toObject() { return { version: this.version, prevblockidbuf: this.prevblockidbuf.toString('hex'), @@ -152,6 +152,13 @@ BlockHeader.prototype.toJSON = function toJSON() { }; }; +/** + * @returns {String} - A JSON string + */ +BlockHeader.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + /** * @returns {Buffer} - A Buffer of the BlockHeader */ diff --git a/lib/crypto/bn.js b/lib/crypto/bn.js index 1625d32c7..1eb8c2aba 100644 --- a/lib/crypto/bn.js +++ b/lib/crypto/bn.js @@ -19,16 +19,6 @@ var reversebuf = function(buf) { return buf2; }; -BN.prototype.toJSON = function() { - return this.toString(); -}; - -BN.prototype.fromJSON = function(str) { - var bn = BN(str); - bn.copy(this); - return this; -}; - BN.prototype.fromNumber = function(n) { var bn = BN(n); bn.copy(this); diff --git a/lib/encoding/varint.js b/lib/encoding/varint.js index 0ba7f106a..c434f4dff 100644 --- a/lib/encoding/varint.js +++ b/lib/encoding/varint.js @@ -26,14 +26,14 @@ Varint.prototype.set = function(obj) { return this; }; -Varint.prototype.fromJSON = function(json) { +Varint.prototype.fromString = function(str) { this.set({ - buf: new Buffer(json, 'hex') + buf: new Buffer(str, 'hex') }); return this; }; -Varint.prototype.toJSON = function() { +Varint.prototype.toString = function() { return this.buf.toString('hex'); }; diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js index 0145912c8..b1b4862fd 100644 --- a/lib/hdprivatekey.js +++ b/lib/hdprivatekey.js @@ -406,7 +406,7 @@ HDPrivateKey.prototype.toString = function() { * * @return {Object} */ -HDPrivateKey.prototype.toJSON = function() { +HDPrivateKey.prototype.toObject = function toObject() { return { network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), @@ -420,6 +420,10 @@ HDPrivateKey.prototype.toJSON = function() { }; }; +HDPrivateKey.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + HDPrivateKey.DefaultDepth = 0; HDPrivateKey.DefaultFingerprint = 0; HDPrivateKey.DefaultChildIndex = 0; diff --git a/lib/hdpublickey.js b/lib/hdpublickey.js index 7a64019d6..2c0ff6e8d 100644 --- a/lib/hdpublickey.js +++ b/lib/hdpublickey.js @@ -366,7 +366,7 @@ HDPublicKey.prototype.toString = function () { * * xpubkey: the string with the base58 representation of this extended key * * checksum: the base58 checksum of xpubkey */ -HDPublicKey.prototype.toJSON = function () { +HDPublicKey.prototype.toObject = function toObject() { return { network: Network.get(BufferUtil.integerFromBuffer(this._buffers.version)).name, depth: BufferUtil.integerFromSingleByteBuffer(this._buffers.depth), @@ -380,6 +380,10 @@ HDPublicKey.prototype.toJSON = function () { }; }; +HDPublicKey.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + HDPublicKey.Hardened = 0x80000000; HDPublicKey.RootElementAlias = ['m', 'M']; diff --git a/lib/privatekey.js b/lib/privatekey.js index 948e3a532..e9b5ea374 100644 --- a/lib/privatekey.js +++ b/lib/privatekey.js @@ -310,11 +310,9 @@ PrivateKey.prototype.toAddress = function() { }; /** - * Will output the PrivateKey to a WIF string - * - * @returns {String} A WIF representation of the private key + * @returns {Object} A plain object representation */ -PrivateKey.prototype.toJSON = function() { +PrivateKey.prototype.toObject = function toObject() { return { bn: this.bn.toString('hex'), compressed: this.compressed, @@ -322,6 +320,10 @@ PrivateKey.prototype.toJSON = function() { }; }; +PrivateKey.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + /** * Will output the PrivateKey to a WIF string * diff --git a/lib/publickey.js b/lib/publickey.js index d9fbc2b48..a50afdf66 100644 --- a/lib/publickey.js +++ b/lib/publickey.js @@ -6,7 +6,6 @@ var Point = require('./crypto/point'); var JSUtil = require('./util/js'); /** - * * Instantiate a PublicKey from a 'PrivateKey', 'Point', 'string', 'Buffer'. * * @example @@ -137,7 +136,6 @@ PublicKey._transformDER = function(buf){ }; /** - * * Internal function to transform X into a public key point * * @param {Boolean} odd - If the point is above or below the x axis @@ -155,7 +153,6 @@ PublicKey._transformX = function(odd, x){ }; /** - * * Instantiate a PublicKey from JSON * * @param {String} json - A JSON string @@ -172,7 +169,6 @@ PublicKey.fromJSON = function(json) { }; /** - * * Instantiate a PublicKey from a PrivateKey * * @param {PrivateKey} privkey - An instance of PrivateKey @@ -184,7 +180,6 @@ PublicKey.fromPrivateKey = function(privkey) { }; /** - * * Instantiate a PublicKey from a Buffer * * @param {Buffer} buf - A DER hex buffer @@ -196,7 +191,6 @@ PublicKey.fromBuffer = function(buf) { }; /** - * * Instantiate a PublicKey from a Point * * @param {Point} point - A Point instance @@ -210,7 +204,6 @@ PublicKey.fromPoint = function(point, compressed){ }; /** - * * Instantiate a PublicKey from a DER Buffer * * @param {Buffer} buf - A DER Buffer @@ -222,7 +215,6 @@ PublicKey.fromDER = function(buf) { }; /** - * * Instantiate a PublicKey from a DER hex encoded string * * @param {String} str - A DER hex string @@ -236,7 +228,6 @@ PublicKey.fromString = function(str, encoding) { }; /** - * * Instantiate a PublicKey from an X Point * * @param {Boolean} odd - If the point is above or below the x axis @@ -250,7 +241,6 @@ PublicKey.fromX = function(odd, x) { /** - * * Check if there would be any errors when initializing a PublicKey * * @param {String} data - The encoded data in various formats @@ -268,7 +258,6 @@ PublicKey.getValidationError = function(data) { }; /** - * * Check if the parameters are valid * * @param {String} data - The encoded data in various formats @@ -280,12 +269,9 @@ PublicKey.isValid = function(data) { }; /** - * - * Will output the PublicKey to JSON - * - * @returns {Object} A JSON object + * @returns {Object} A plain object of the PublicKey */ -PublicKey.prototype.toJSON = function() { +PublicKey.prototype.toObject = function toObject() { return { x: this.point.getX().toString('hex'), y: this.point.getY().toString('hex'), @@ -293,8 +279,11 @@ PublicKey.prototype.toJSON = function() { }; }; +PublicKey.prototype.toJSON = function toJSON(){ + return JSON.stringify(this.toObject()); +}; + /** - * * Will output the PublicKey to a Buffer * * @returns {Buffer} A DER hex encoded buffer @@ -305,7 +294,6 @@ PublicKey.prototype.toBuffer = function() { }; /** - * * Will output the PublicKey to a DER Buffer * * @returns {Buffer} A DER hex encoded buffer @@ -338,7 +326,6 @@ PublicKey.prototype.toDER = function(compressed) { }; /** - * * Will return an address for the public key * * @returns {Address} An address generated from the public key @@ -348,7 +335,6 @@ PublicKey.prototype.toAddress = function(network) { }; /** - * * Will output the PublicKey to a DER encoded hex string * * @returns {String} A DER hex encoded string @@ -359,7 +345,6 @@ PublicKey.prototype.toString = function() { }; /** - * * Will return a string formatted for the console * * @returns {String} Public key diff --git a/lib/transaction/input/input.js b/lib/transaction/input/input.js index 577553947..3a4f5b118 100644 --- a/lib/transaction/input/input.js +++ b/lib/transaction/input/input.js @@ -4,7 +4,7 @@ var _ = require('lodash'); var BufferWriter = require('../../encoding/bufferwriter'); var buffer = require('buffer'); var bufferUtil = require('../../util/buffer'); -var jsUtil = require('../../util/js'); +var JSUtil = require('../../util/js'); var Script = require('../../script'); function Input(params) { @@ -28,7 +28,7 @@ Object.defineProperty(Input.prototype, 'script', { }); Input.prototype._fromObject = function(params) { - if (_.isString(params.prevTxId) && jsUtil.isHexa(params.prevTxId)) { + if (_.isString(params.prevTxId) && JSUtil.isHexa(params.prevTxId)) { params.prevTxId = new buffer.Buffer(params.prevTxId, 'hex'); } this.prevTxId = params.prevTxId; @@ -40,7 +40,7 @@ Input.prototype._fromObject = function(params) { return this; }; -Input.prototype.toJSON = function() { +Input.prototype.toObject = function toObject() { return { prevTxId: this.prevTxId, outputIndex: this.outputIndex, @@ -49,7 +49,14 @@ Input.prototype.toJSON = function() { }; }; +Input.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + Input.fromJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } return new Input({ prevTxId: json.prevTxId || json.txidbuf, outputIndex: json.outputIndex || json.txoutnum, diff --git a/lib/transaction/output.js b/lib/transaction/output.js index 97385f1b2..759aeacaf 100644 --- a/lib/transaction/output.js +++ b/lib/transaction/output.js @@ -4,6 +4,7 @@ var _ = require('lodash'); var BN = require('../crypto/bn'); var buffer = require('buffer'); var bufferUtil = require('../util/buffer'); +var JSUtil = require('../util/js'); var BufferWriter = require('../encoding/bufferwriter'); var Script = require('../script'); @@ -53,14 +54,21 @@ Output.prototype._fromObject = function(param) { return this; }; -Output.prototype.toJSON = function() { +Output.prototype.toObject = function toObject() { return { satoshis: this.satoshis, script: this._scriptBuffer.toString('hex') }; }; +Output.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + Output.fromJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } return new Output({ satoshis: json.satoshis || -(-json.valuebn), script: new Script(json.script) diff --git a/lib/transaction/transaction.js b/lib/transaction/transaction.js index 9593479d4..654efe7ba 100644 --- a/lib/transaction/transaction.js +++ b/lib/transaction/transaction.js @@ -6,6 +6,7 @@ var assert = require('assert'); var util = require('../util/js'); var bufferUtil = require('../util/buffer'); +var JSUtil = require('../util/js'); var BufferReader = require('../encoding/bufferreader'); var BufferWriter = require('../encoding/bufferwriter'); var Hash = require('../crypto/hash'); @@ -121,6 +122,9 @@ Transaction.prototype.fromBufferReader = function(reader) { }; Transaction.prototype.fromJSON = function(json) { + if (JSUtil.isValidJSON(json)) { + json = JSON.parse(json); + } var self = this; this.inputs = []; var inputs = json.inputs || json.txins; @@ -137,7 +141,7 @@ Transaction.prototype.fromJSON = function(json) { return this; }; -Transaction.prototype.toJSON = function() { +Transaction.prototype.toObject = function toObject() { var inputs = []; this.inputs.forEach(function(input) { inputs.push(input.toJSON()); @@ -154,11 +158,12 @@ Transaction.prototype.toJSON = function() { }; }; -Transaction.prototype.fromString = function(string) { - this.fromBuffer(new buffer.Buffer(string, 'hex')); +Transaction.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); }; -Transaction.prototype.fromObject = function(object) { +Transaction.prototype.fromString = function(string) { + this.fromBuffer(new buffer.Buffer(string, 'hex')); }; Transaction.prototype._newTransaction = function() { diff --git a/lib/unit.js b/lib/unit.js index dc6bb7433..45a2dfdf3 100644 --- a/lib/unit.js +++ b/lib/unit.js @@ -175,17 +175,21 @@ Unit.prototype.toString = function() { }; /** - * Will return a the JSON object representation of the unit + * Will return a plain object representation of the Unit * * @returns {Object} An object with the keys: amount and code */ -Unit.prototype.toJSON = function toJSON(){ +Unit.prototype.toObject = function toObject() { return { amount: this._amount, code: this._code }; }; +Unit.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + /** * Will return a string formatted for the console * diff --git a/lib/uri.js b/lib/uri.js index 8013cf7f4..a551605e8 100644 --- a/lib/uri.js +++ b/lib/uri.js @@ -163,7 +163,7 @@ URI.prototype._parseAmount = function(amount) { return Unit.fromBTC(amount).toSatoshis(); }; -URI.prototype.toJSON = function() { +URI.prototype.toObject = function toObject() { var json = {}; for (var i = 0; i < URI.Members.length; i++) { var m = URI.Members[i]; @@ -179,6 +179,10 @@ URI.prototype.toJSON = function() { return json; }; +URI.prototype.toJSON = function toJSON() { + return JSON.stringify(this.toObject()); +}; + /** * Will return a the string representation of the URI * diff --git a/test/address.js b/test/address.js index 704a3c388..54918616d 100644 --- a/test/address.js +++ b/test/address.js @@ -363,7 +363,7 @@ describe('Address', function() { }); it('should output/input a JSON string', function() { - var json = JSON.stringify(new Address(str).toJSON()); + var json = new Address(str).toJSON(); var address = Address.fromJSON(json); address.toString().should.equal(str); }); diff --git a/test/block.js b/test/block.js index fdd421ef6..148a55259 100644 --- a/test/block.js +++ b/test/block.js @@ -107,8 +107,8 @@ describe('Block', function() { describe('#toJSON', function() { it('should recover these known values', function() { - var block = Block(json); - var b = block.toJSON(); + var block = Block.fromJSON(json); + var b = JSON.parse(block.toJSON()); should.exist(b.magicnum); should.exist(b.blocksize); should.exist(b.blockheader); diff --git a/test/blockheader.js b/test/blockheader.js index 4fed3a17a..6e226a312 100644 --- a/test/blockheader.js +++ b/test/blockheader.js @@ -87,7 +87,7 @@ describe('BlockHeader', function() { describe('#toJSON', function() { it('should set all the variables', function() { - var json = bh.toJSON(); + var json = JSON.parse(bh.toJSON()); should.exist(json.version); should.exist(json.prevblockidbuf); should.exist(json.merklerootbuf); diff --git a/test/crypto/bn.js b/test/crypto/bn.js index 298c8d4c5..a771ae0f9 100644 --- a/test/crypto/bn.js +++ b/test/crypto/bn.js @@ -67,23 +67,6 @@ describe('BN', function() { }); - describe('#fromJSON', function() { - - it('should make BN from a string', function() { - BN().fromJSON('5').toString().should.equal('5'); - }); - - }); - - describe('#toJSON', function() { - - it('should make string from a BN', function() { - BN(5).toJSON().should.equal('5'); - BN().fromJSON('5').toJSON().should.equal('5'); - }); - - }); - describe('#fromString', function() { it('should make BN from a string', function() { diff --git a/test/encoding/varint.js b/test/encoding/varint.js index 9a8bb8440..2ee6b2cd7 100644 --- a/test/encoding/varint.js +++ b/test/encoding/varint.js @@ -36,22 +36,22 @@ describe('Varint', function() { }); - describe('#fromJSON', function() { + describe('#fromString', function() { it('should set a buffer', function() { var buf = BufferWriter().writeVarintNum(5).concat(); - var varint = Varint().fromJSON(buf.toString('hex')); + var varint = Varint().fromString(buf.toString('hex')); varint.toNumber().should.equal(5); }); }); - describe('#toJSON', function() { + describe('#toString', function() { it('should return a buffer', function() { var buf = BufferWriter().writeVarintNum(5).concat(); - var varint = Varint().fromJSON(buf.toString('hex')); - varint.toJSON().should.equal('05'); + var varint = Varint().fromString(buf.toString('hex')); + varint.toString().should.equal('05'); }); }); diff --git a/test/privatekey.js b/test/privatekey.js index 8ba951ec5..92dac7156 100644 --- a/test/privatekey.js +++ b/test/privatekey.js @@ -132,11 +132,11 @@ describe('PrivateKey', function() { describe('#json', function() { it('should input/output json', function() { - var json = { + var json = JSON.stringify({ bn: '96c132224121b509b7d0a16245e957d9192609c5637c6228311287b1be21627a', compressed: false, network: 'livenet' - }; + }); PrivateKey.fromJSON(json).toJSON().should.deep.equal(json); }); diff --git a/test/publickey.js b/test/publickey.js index fd74f3286..f93e951dd 100644 --- a/test/publickey.js +++ b/test/publickey.js @@ -124,11 +124,11 @@ describe('PublicKey', function() { describe('#json', function() { it('should input/ouput json', function() { - var json = { + var json = JSON.stringify({ x: '1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', y: '7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', compressed: false - }; + }); PublicKey.fromJSON(json).toJSON().should.deep.equal(json); }); diff --git a/test/unit.js b/test/unit.js index 87fc82fab..063fa6dd9 100644 --- a/test/unit.js +++ b/test/unit.js @@ -124,7 +124,7 @@ describe('Unit', function() { }); it('should input/output JSON', function() { - var json = {amount:1.3, code:'BTC'}; + var json = JSON.stringify({amount:1.3, code:'BTC'}); var unit = Unit.fromJSON(json); unit.toJSON().should.deep.equal(json); }); diff --git a/test/uri.js b/test/uri.js index e0b135e15..aad0934a6 100644 --- a/test/uri.js +++ b/test/uri.js @@ -146,12 +146,12 @@ describe('URI', function() { }); it('should input/output JSON', function() { - var json = { + var json = JSON.stringify({ address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj', message: 'Donation for project xyz', label: 'myLabel', other: 'xD' - }; + }); URI.fromJSON(json).toJSON().should.deep.equal(json); });