From 2f163c3b6edd4119735ee7118aca0dde1b7e09fe Mon Sep 17 00:00:00 2001 From: Chris Clark Date: Fri, 2 Oct 2015 14:50:36 -0700 Subject: [PATCH] Decouple UInt from non-serialization code --- src/api/common/schema-validator.js | 15 +--- src/core/autobridgecalculator.js | 47 ++++++----- src/core/currency.js | 107 ++++++++++++++++++++++++-- src/core/index.js | 9 ++- src/core/meta.js | 3 +- src/core/orderbook.js | 18 ++--- src/core/orderbookutils.js | 10 +-- src/core/remote.js | 54 ++++++------- src/core/request.js | 15 ++-- src/core/transaction.js | 25 +++--- test/amount-test.js | 22 ------ test/fixtures/schemas/ledgerhash.json | 2 +- test/remote-test.js | 21 +++-- test/transaction-test.js | 3 +- test/uint-test.js | 24 +++++- 15 files changed, 217 insertions(+), 158 deletions(-) diff --git a/src/api/common/schema-validator.js b/src/api/common/schema-validator.js index db4f99db..f71c6183 100644 --- a/src/api/common/schema-validator.js +++ b/src/api/common/schema-validator.js @@ -4,21 +4,11 @@ const _ = require('lodash'); const assert = require('assert'); const validator = require('is-my-json-valid'); -const core = require('./utils').core; const ValidationError = require('./errors').ValidationError; +const {isValidAddress} = require('ripple-address-codec'); let SCHEMAS = {}; -function isValidAddress(address: string): boolean { - return typeof address === 'string' && address.length > 0 && - address[0] === 'r' && - core.UInt160.is_valid(address); -} - -function isValidLedgerHash(ledgerHash) { - return core.UInt256.is_valid(ledgerHash); -} - function loadSchemas() { // listed explicitly for webpack (instead of scanning schemas directory) const schemas = [ @@ -100,8 +90,7 @@ function formatSchemaErrors(errors) { } function schemaValidate(schemaName: string, object: any): void { - const formats = {address: isValidAddress, - ledgerHash: isValidLedgerHash}; + const formats = {address: isValidAddress}; const options = {schemas: SCHEMAS, formats: formats, verbose: true, greedy: true}; const schema = SCHEMAS[schemaName]; diff --git a/src/core/autobridgecalculator.js b/src/core/autobridgecalculator.js index d3848337..b708e7ca 100644 --- a/src/core/autobridgecalculator.js +++ b/src/core/autobridgecalculator.js @@ -3,7 +3,6 @@ const _ = require('lodash'); const assert = require('assert'); const Amount = require('./amount').Amount; -const UInt160 = require('./uint160').UInt160; const Utils = require('./orderbookutils'); function assertValidNumber(number, message) { @@ -25,9 +24,7 @@ function AutobridgeCalculator(currencyGets, currencyPays, this._currencyGetsHex = currencyGets.to_hex(); this._currencyPaysHex = currencyPays.to_hex(); this._issuerGets = issuerGets; - this._issuerGetsObj = UInt160.from_json(issuerGets); this._issuerPays = issuerPays; - this._issuerPaysObj = UInt160.from_json(issuerPays); this.legOneOffers = _.cloneDeep(legOneOffers); this.legTwoOffers = _.cloneDeep(legTwoOffers); @@ -94,9 +91,9 @@ AutobridgeCalculator.prototype._calculateInternal = function( } const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer, - this._currencyGets, this._issuerGetsObj); + this._currencyGets, this._issuerGets); if (legOneTakerGetsFunded.is_zero()) { legOnePointer++; @@ -157,19 +154,19 @@ AutobridgeCalculator.prototype._calculateInternal = function( AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegOne = function(legOneOffer, legTwoOffer) { const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer, - this._currencyGets, this._issuerGetsObj); + this._currencyGets, this._issuerGets); const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer, - this._currencyGets, this._issuerGetsObj); + this._currencyGets, this._issuerGets); const autobridgedTakerPays = legTwoTakerPaysFunded.multiply(legOneQuality); if (legOneOffer.Account === legTwoOffer.Account) { const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); const updatedTakerGets = legOneTakerGets.subtract(legTwoTakerPaysFunded); this.setLegOneTakerGets(legOneOffer, updatedTakerGets); @@ -202,19 +199,19 @@ function(legOneOffer, legTwoOffer) { AutobridgeCalculator.prototype.getAutobridgedOfferWithClampedLegTwo = function(legOneOffer, legTwoOffer) { const legOneTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); const legTwoTakerPaysFunded = Utils.getOfferTakerPaysFunded(legTwoOffer, - this._currencyGets, this._issuerGetsObj); + this._currencyGets, this._issuerGets); const legTwoQuality = Utils.getOfferQuality(legTwoOffer, this._currencyGets, - this._currencyGets, this._issuerGetsObj); + this._currencyGets, this._issuerGets); const autobridgedTakerGets = legOneTakerGetsFunded.divide(legTwoQuality); const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); // Update funded amount since leg two offer was not completely consumed legTwoOffer.taker_gets_funded = Utils.getOfferTakerGetsFunded(legTwoOffer, - this._currencyGets, this._issuerGetsObj) + this._currencyGets, this._issuerGets) .subtract(autobridgedTakerGets) .to_text(); legTwoOffer.taker_pays_funded = legTwoTakerPaysFunded @@ -239,9 +236,9 @@ function(legOneOffer, legTwoOffer) { AutobridgeCalculator.prototype.getAutobridgedOfferWithoutClamps = function(legOneOffer, legTwoOffer) { const autobridgedTakerGets = Utils.getOfferTakerGetsFunded(legTwoOffer, - this._currencyGets, this._issuerGetsObj); + this._currencyGets, this._issuerGets); const autobridgedTakerPays = Utils.getOfferTakerPaysFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); return this.formatAutobridgedOffer( autobridgedTakerGets, @@ -378,12 +375,12 @@ AutobridgeCalculator.prototype.unclampLegOneOwnerFunds = function(legOneOffer) { assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid'); legOneOffer.initTakerGetsFunded = Utils.getOfferTakerGetsFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); this.setLegOneTakerGetsFunded( legOneOffer, Utils.getOfferTakerGets(legOneOffer, this._currencyPays, - this._issuerPaysObj) + this._issuerPays) ); }; @@ -405,7 +402,7 @@ AutobridgeCalculator.prototype.clampLegOneOwnerFunds = function(legOneOffer) { assertValidLegOneOffer(legOneOffer, 'Leg one offer is invalid'); const takerGets = Utils.getOfferTakerGets(legOneOffer, this._currencyPays, - this._issuerPaysObj); + this._issuerPays); if (takerGets.compareTo(legOneOffer.initTakerGetsFunded) > 0) { // After clamping, TakerGets is still greater than initial funded amount @@ -431,15 +428,15 @@ function(legOneOffer) { assert(!legOneOffer.is_fully_funded, 'Leg one offer cannot be fully funded'); const fundedSum = Utils.getOfferTakerGetsFunded(legOneOffer, - this._currencyPays, this._issuerPaysObj) + this._currencyPays, this._issuerPays) .add(this.getLeftoverOwnerFunds(legOneOffer.Account)); if (fundedSum.compareTo(Utils.getOfferTakerGets(legOneOffer, - this._currencyPays, this._issuerPaysObj)) >= 0 + this._currencyPays, this._issuerPays)) >= 0 ) { // There are enough extra funds to fully fund the offer const legOneTakerGets = Utils.getOfferTakerGets(legOneOffer, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); const updatedLeftover = fundedSum.subtract(legOneTakerGets); this.setLegOneTakerGetsFunded(legOneOffer, legOneTakerGets); @@ -467,7 +464,7 @@ function setLegOneTakerGetsFunded(legOneOffer, takerGetsFunded) { legOneOffer.taker_gets_funded = takerGetsFunded.to_text(); legOneOffer.taker_pays_funded = takerGetsFunded .multiply(Utils.getOfferQuality(legOneOffer, this._currencyGets, - this._currencyPays, this._issuerPaysObj)) + this._currencyPays, this._issuerPays)) .to_text(); if (legOneOffer.taker_gets_funded === legOneOffer.TakerGets.value) { @@ -489,7 +486,7 @@ function(legOneOffer, takerGets) { assert(takerGets instanceof Amount, 'Taker gets funded is invalid'); const legOneQuality = Utils.getOfferQuality(legOneOffer, this._currencyGets, - this._currencyPays, this._issuerPaysObj); + this._currencyPays, this._issuerPays); legOneOffer.TakerGets = takerGets.to_text(); legOneOffer.TakerPays = takerGets.multiply(legOneQuality).to_json(); diff --git a/src/core/currency.js b/src/core/currency.js index a23e97f0..8e97445f 100644 --- a/src/core/currency.js +++ b/src/core/currency.js @@ -1,15 +1,14 @@ 'use strict'; - -const extend = require('extend'); -const UInt160 = require('./uint160').UInt160; +const assert = require('assert'); const utils = require('./utils'); const Float = require('./ieee754').Float; +const BN = require('bn.js'); // // Currency support // -const Currency = extend(function() { +function Currency() { // Internal form: 0 = XRP. 3 letter-code. // XXX Internal should be 0 or hex with three letter annotation when valid. @@ -20,12 +19,12 @@ const Currency = extend(function() { this._value = NaN; this._update(); -}, UInt160); - -Currency.prototype = Object.create(extend({}, UInt160.prototype)); -Currency.prototype.constructor = Currency; +} +Currency.width = 20; Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000'; +Currency.HEX_ZERO = '0000000000000000000000000000000000000000'; +Currency.HEX_ONE = '0000000000000000000000000000000000000001'; /** * Tries to correctly interpret a Currency as entered by a user. @@ -69,10 +68,54 @@ Currency.from_json = function(j, shouldInterpretXrpAsIou) { return (new Currency()).parse_json(j, shouldInterpretXrpAsIou); }; +Currency.from_hex = function(j) { + if (j instanceof this) { + return j.clone(); + } + + return (new this()).parse_hex(j); +}; + +Currency.from_bytes = function(j) { + if (j instanceof this) { + return j.clone(); + } + + return (new this()).parse_bytes(j); +}; + +Currency.prototype.to_hex = function() { + if (!this.is_valid()) { + return null; + } + + return utils.arrayToHex(this.to_bytes()); +}; + Currency.from_human = function(j, opts) { return (new Currency().parse_human(j, opts)); }; +Currency.json_rewrite = function(j, opts) { + return this.from_json(j).to_json(opts); +}; + +Currency.prototype.clone = function() { + return this.copyTo(new this.constructor()); +}; + +Currency.prototype.equals = function(o) { + return this.is_valid() && + o.is_valid() && + // This throws but the expression will short circuit + this.cmp(o) === 0; +}; + +Currency.prototype.cmp = function(o) { + assert(this.is_valid() && o.is_valid()); + return this._value.cmp(o._value); +}; + // this._value = NaN on error. Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) { this._value = NaN; @@ -197,6 +240,40 @@ Currency.prototype.parse_human = function(j) { return this.parse_json(j); }; +Currency.prototype.is_valid = function() { + return this._value instanceof BN; +}; + +Currency.prototype.parse_number = function(j) { + this._value = NaN; + + if (typeof j === 'number' && isFinite(j) && j >= 0) { + this._value = new BN(j); + } + + this._update(); + return this; +}; + +Currency.prototype.parse_hex = function(j) { + if (new RegExp(`^[0-9A-Fa-f]{${this.constructor.width * 2}}$`).test(j)) { + this._value = new BN(j, 16); + } else { + this._value = NaN; + } + + this._update(); + return this; +}; + +Currency.prototype.to_bytes = function() { + if (!this.is_valid()) { + return null; + } + + return this._value.toArray('be', this.constructor.width); +}; + /** * Recalculate internal representation. * @@ -276,6 +353,16 @@ Currency.prototype.copyTo = function(d) { return d; }; +Currency.prototype.parse_bytes = function(j) { + if (Array.isArray(j) && j.length === this.constructor.width) { + this._value = new BN(j); + } else { + this._value = NaN; + } + + this._update(); + return this; +}; // XXX Probably not needed anymore? /* @@ -426,4 +513,8 @@ Currency.prototype.get_iso = function() { return this._iso_code; }; +Currency.is_valid = function(j) { + return this.from_json(j).is_valid(); +}; + exports.Currency = Currency; diff --git a/src/core/index.js b/src/core/index.js index 597855a7..a109387c 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -6,9 +6,6 @@ exports.Account = require('./account').Account; exports.Transaction = require('./transaction').Transaction; exports.Currency = require('./currency').Currency; exports.Base = require('./base').Base; -exports.UInt128 = require('./uint128').UInt128; -exports.UInt160 = require('./uint160').UInt160; -exports.UInt256 = require('./uint256').UInt256; exports.Meta = require('./meta').Meta; exports.SerializedObject = require('./serializedobject').SerializedObject; exports.RippleError = require('./rippleerror').RippleError; @@ -24,7 +21,11 @@ exports._test = { PathFind: require('./pathfind').PathFind, TransactionManager: require('./transactionmanager').TransactionManager, RangeSet: require('./rangeset').RangeSet, - HashPrefixes: require('./hashprefixes') + HashPrefixes: require('./hashprefixes'), + UInt128: require('./uint128').UInt128, + UInt160: require('./uint160').UInt160, + UInt256: require('./uint256').UInt256, + constants: require('./constants') }; exports.types = require('./serializedtypes'); diff --git a/src/core/meta.js b/src/core/meta.js index d1b026c3..ab6c78c5 100644 --- a/src/core/meta.js +++ b/src/core/meta.js @@ -1,7 +1,6 @@ 'use strict'; const extend = require('extend'); const utils = require('./utils'); -const UInt160 = require('./uint160').UInt160; const Amount = require('./amount').Amount; const ACCOUNT_ZERO = require('./constants').ACCOUNT_ZERO; const {isValidAddress} = require('ripple-address-codec'); @@ -151,7 +150,7 @@ Meta.prototype.getAffectedAccounts = function() { for (const fieldName in fields) { const field = fields[fieldName]; - if (this.isAccountField(fieldName) && UInt160.is_valid(field)) { + if (this.isAccountField(fieldName) && isValidAddress(field)) { accounts.push(field); } else if ( Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName) !== -1) { diff --git a/src/core/orderbook.js b/src/core/orderbook.js index b1a997d9..2c65cfbb 100644 --- a/src/core/orderbook.js +++ b/src/core/orderbook.js @@ -16,8 +16,8 @@ const extend = require('extend'); const assert = require('assert'); const async = require('async'); const EventEmitter = require('events').EventEmitter; +const {isValidAddress} = require('ripple-address-codec'); const Amount = require('./amount').Amount; -const UInt160 = require('./uint160').UInt160; const Currency = require('./currency').Currency; const AutobridgeCalculator = require('./autobridgecalculator'); const OrderBookUtils = require('./orderbookutils'); @@ -795,7 +795,7 @@ OrderBook.prototype.parseAccountBalanceFromNode = function(node) { assert(!isNaN(result.balance), 'node has an invalid balance'); if (this._validAccounts[result.Account] === undefined) { - assert(UInt160.is_valid(result.account), 'node has an invalid account'); + assert(isValidAddress(result.account), 'node has an invalid account'); this._validAccounts[result.Account] = true; this._validAccountsCount++; } @@ -920,8 +920,6 @@ OrderBook.prototype.updateFundedAmounts = function(transaction) { */ OrderBook.prototype.updateOwnerOffersFundedAmount = function(account) { - // assert(UInt160.is_valid(account), 'Account is invalid'); - const self = this; if (!this.hasOwnerFunds(account)) { @@ -1027,7 +1025,7 @@ OrderBook.prototype.notify = function(transaction) { switch (node.nodeType) { case 'DeletedNode': if (self._validAccounts[node.fields.Account] === undefined) { - assert(UInt160.is_valid(node.fields.Account), + assert(isValidAddress(node.fields.Account), 'node has an invalid account'); self._validAccounts[node.fields.Account] = true; self._validAccountsCount++; @@ -1043,7 +1041,7 @@ OrderBook.prototype.notify = function(transaction) { case 'ModifiedNode': if (self._validAccounts[node.fields.Account] === undefined) { - assert(UInt160.is_valid(node.fields.Account), + assert(isValidAddress(node.fields.Account), 'node has an invalid account'); self._validAccounts[node.fields.Account] = true; self._validAccountsCount++; @@ -1061,7 +1059,7 @@ OrderBook.prototype.notify = function(transaction) { case 'CreatedNode': if (self._validAccounts[node.fields.Account] === undefined) { - assert(UInt160.is_valid(node.fields.Account), + assert(isValidAddress(node.fields.Account), 'node has an invalid account'); self._validAccounts[node.fields.Account] = true; self._validAccountsCount++; @@ -1249,7 +1247,7 @@ OrderBook.prototype.setOffers = function(offers) { offer = OrderBook.offerRewrite(offers[i]); if (this._validAccounts[offer.Account] === undefined) { - assert(UInt160.is_valid(offer.Account), 'Account is invalid'); + assert(isValidAddress(offer.Account), 'Account is invalid'); this._validAccounts[offer.Account] = true; this._validAccountsCount++; } @@ -1353,9 +1351,9 @@ OrderBook.prototype.is_valid = function() { // XXX Should check for same currency (non-native) && same issuer return ( this._currencyPays && this._currencyPays.is_valid() && - (this._currencyPays.is_native() || UInt160.is_valid(this._issuerPays)) && + (this._currencyPays.is_native() || isValidAddress(this._issuerPays)) && this._currencyGets && this._currencyGets.is_valid() && - (this._currencyGets.is_native() || UInt160.is_valid(this._issuerGets)) && + (this._currencyGets.is_native() || isValidAddress(this._issuerGets)) && !(this._currencyPays.is_native() && this._currencyGets.is_native()) ); }; diff --git a/src/core/orderbookutils.js b/src/core/orderbookutils.js index 462bc333..eae49353 100644 --- a/src/core/orderbookutils.js +++ b/src/core/orderbookutils.js @@ -2,11 +2,11 @@ const _ = require('lodash'); const assert = require('assert'); +const constants = require('./constants'); const SerializedObject = require('./serializedobject').SerializedObject; const Types = require('./serializedtypes'); const Amount = require('./amount').Amount; const Currency = require('./currency').Currency; -const UInt160 = require('./uint160').UInt160; const {IOUValue} = require('ripple-lib-value'); const OrderBookUtils = {}; @@ -22,15 +22,13 @@ function assertValidNumber(number, message) { * @return JSON amount object */ -function createAmount(value, currency_, counterparty_) { +function createAmount(value, currency_, counterparty) { + assert(_.isString(counterparty), 'counterparty must be a string'); const currency = currency_ instanceof Currency ? currency_ : Currency.from_json(currency_); - const counterparty = counterparty_ instanceof UInt160 ? - counterparty_.to_json() : counterparty_; - return Amount.from_components_unsafe(new IOUValue(value), currency, counterparty, false); } @@ -172,7 +170,7 @@ OrderBookUtils.convertOfferQualityToHexFromText = function(quality) { OrderBookUtils.CURRENCY_ONE = Currency.from_json(1); -OrderBookUtils.ISSUER_ONE = UInt160.from_json(1); +OrderBookUtils.ISSUER_ONE = constants.ACCOUNT_ONE; /** * diff --git a/src/core/remote.js b/src/core/remote.js index 7268c7ad..beef0cdb 100644 --- a/src/core/remote.js +++ b/src/core/remote.js @@ -18,13 +18,12 @@ const assert = require('assert'); const _ = require('lodash'); const LRU = require('lru-cache'); const async = require('async'); +const constants = require('./constants'); const EventEmitter = require('events').EventEmitter; const Server = require('./server').Server; const Request = require('./request').Request; const Amount = require('./amount').Amount; const Currency = require('./currency').Currency; -const UInt160 = require('./uint160').UInt160; -const UInt256 = require('./uint256').UInt256; const Transaction = require('./transaction').Transaction; const Account = require('./account').Account; const Meta = require('./meta').Meta; @@ -35,6 +34,7 @@ const RippleError = require('./rippleerror').RippleError; const utils = require('./utils'); const hashprefixes = require('./hashprefixes'); const log = require('./log').internal.sub('remote'); +const {isValidAddress} = require('ripple-address-codec'); export type GetLedgerSequenceCallback = (err?: ?Error, index?: number) => void; @@ -1188,9 +1188,13 @@ Remote.prototype.requestTransaction = function(options, callback) { * @throws {Error} if a marker is provided, but no ledger_index or ledger_hash */ +function isValidLedgerHash(hash) { + return /^[A-F0-9]{64}$/.test(hash); +} + Remote.prototype._accountRequest = function(command, options, callback) { if (options.marker) { - if (!(Number(options.ledger) > 0) && !UInt256.is_valid(options.ledger)) { + if (!(Number(options.ledger) > 0) && !isValidLedgerHash(options.ledger)) { throw new Error( 'A ledger_index or ledger_hash must be provided when using a marker'); } @@ -1198,11 +1202,11 @@ Remote.prototype._accountRequest = function(command, options, callback) { const request = new Request(this, command); - request.message.account = UInt160.json_rewrite(options.account); + request.message.account = options.account; request.selectLedger(options.ledger); - if (UInt160.is_valid(options.peer)) { - request.message.peer = UInt160.json_rewrite(options.peer); + if (isValidAddress(options.peer)) { + request.message.peer = options.peer; } if (!isNaN(options.limit)) { @@ -1530,7 +1534,7 @@ Remote.prototype.requestBookOffers = function(options, callback) { }; if (!Currency.from_json(request.message.taker_gets.currency).is_native()) { - request.message.taker_gets.issuer = UInt160.json_rewrite(taker_gets.issuer); + request.message.taker_gets.issuer = taker_gets.issuer; } request.message.taker_pays = { @@ -1538,10 +1542,10 @@ Remote.prototype.requestBookOffers = function(options, callback) { }; if (!Currency.from_json(request.message.taker_pays.currency).is_native()) { - request.message.taker_pays.issuer = UInt160.json_rewrite(taker_pays.issuer); + request.message.taker_pays.issuer = taker_pays.issuer; } - request.message.taker = taker ? taker : UInt160.ACCOUNT_ONE; + request.message.taker = taker ? taker : constants.ACCOUNT_ONE; request.selectLedger(ledger); if (!isNaN(limit)) { @@ -1775,7 +1779,7 @@ Remote.prototype.requestOwnerCount = function(options, callback) { */ Remote.prototype.getAccount = function(accountID) { - return this._accounts[UInt160.json_rewrite(accountID)]; + return this._accounts[accountID]; }; /** @@ -1899,8 +1903,7 @@ Remote.prototype.book = Remote.prototype.createOrderBook = function(options) { */ Remote.prototype.accountSeq = -Remote.prototype.getAccountSequence = function(account_, advance) { - const account = UInt160.json_rewrite(account_); +Remote.prototype.getAccountSequence = function(account, advance) { const accountInfo = this.accounts[account]; if (!accountInfo) { @@ -1923,9 +1926,7 @@ Remote.prototype.getAccountSequence = function(account_, advance) { */ Remote.prototype.setAccountSequence = -Remote.prototype.setAccountSeq = function(account_, sequence) { - const account = UInt160.json_rewrite(account_); - +Remote.prototype.setAccountSeq = function(account, sequence) { if (!this.accounts.hasOwnProperty(account)) { this.accounts[account] = { }; } @@ -1991,8 +1992,7 @@ Remote.prototype.accountSeqCache = function(options, callback) { * @param {String} account */ -Remote.prototype.dirtyAccountRoot = function(account_) { - const account = UInt160.json_rewrite(account_); +Remote.prototype.dirtyAccountRoot = function(account) { delete this.ledgers.current.account_root[account]; }; @@ -2065,8 +2065,7 @@ Remote.prototype.requestRippleBalance = function(options, callback) { // accountHigh implies for account: balance is negated. highLimit is the // limit set by account. - const accountHigh = UInt160.from_json(options.account) - .equals(highLimit.issuer()); + const accountHigh = (options.account === highLimit.issuer()); request.emit('ripple_state', { account_balance: (accountHigh @@ -2107,7 +2106,7 @@ Remote.prepareCurrencies = function(currency) { const newCurrency = { }; if (currency.hasOwnProperty('issuer')) { - newCurrency.issuer = UInt160.json_rewrite(currency.issuer); + newCurrency.issuer = currency.issuer; } if (currency.hasOwnProperty('currency')) { @@ -2128,12 +2127,8 @@ Remote.prepareCurrencies = function(currency) { Remote.prototype.requestRipplePathFind = function(options, callback) { const request = new Request(this, 'ripple_path_find'); - - request.message.source_account = UInt160.json_rewrite(options.source_account); - - request.message.destination_account = - UInt160.json_rewrite(options.destination_account); - + request.message.source_account = options.source_account; + request.message.destination_account = options.destination_account; request.message.destination_amount = Amount.json_rewrite(options.destination_amount); @@ -2159,11 +2154,8 @@ Remote.prototype.requestPathFindCreate = function(options, callback) { const request = new Request(this, 'path_find'); request.message.subcommand = 'create'; - request.message.source_account = UInt160.json_rewrite(options.source_account); - - request.message.destination_account = - UInt160.json_rewrite(options.destination_account); - + request.message.source_account = options.source_account; + request.message.destination_account = options.destination_account; request.message.destination_amount = Amount.json_rewrite(options.destination_amount); diff --git a/src/core/request.js b/src/core/request.js index ea9046d4..a0483c74 100644 --- a/src/core/request.js +++ b/src/core/request.js @@ -4,7 +4,6 @@ const _ = require('lodash'); const EventEmitter = require('events').EventEmitter; const util = require('util'); const async = require('async'); -const UInt160 = require('./uint160').UInt160; const Currency = require('./currency').Currency; const RippleError = require('./rippleerror').RippleError; @@ -388,7 +387,7 @@ Request.prototype.selectLedger = function(ledger, defaultValue) { }; Request.prototype.accountRoot = function(account) { - this.message.account_root = UInt160.json_rewrite(account); + this.message.account_root = account; return this; }; @@ -402,7 +401,7 @@ Request.prototype.index = function(index) { // --> seq : sequence number of transaction creating offer (integer) Request.prototype.offerId = function(account, sequence) { this.message.offer = { - account: UInt160.json_rewrite(account), + account: account, seq: sequence }; return this; @@ -440,8 +439,8 @@ Request.prototype.rippleState = function(account, issuer, currency) { this.message.ripple_state = { currency: currency, accounts: [ - UInt160.json_rewrite(account), - UInt160.json_rewrite(issuer) + account, + issuer ] }; return this; @@ -453,7 +452,7 @@ Request.prototype.accounts = function(accountsIn, proposed) { // Process accounts parameters const processedAccounts = accounts.map(function(account) { - return UInt160.json_rewrite(account); + return account; }); if (proposed) { @@ -471,7 +470,7 @@ Request.prototype.addAccount = function(account, proposed) { return this; } - const processedAccount = UInt160.json_rewrite(account); + const processedAccount = account; const prop = proposed === true ? 'accounts_proposed' : 'accounts'; this.message[prop] = (this.message[prop] || []).concat(processedAccount); @@ -526,7 +525,7 @@ Request.prototype.addBook = function(book, snapshot) { }; if (!Currency.from_json(obj.currency).is_native()) { - obj.issuer = UInt160.json_rewrite(book[side].issuer); + obj.issuer = book[side].issuer; } } diff --git a/src/core/transaction.js b/src/core/transaction.js index 6cd0a7ab..130ba1e7 100644 --- a/src/core/transaction.js +++ b/src/core/transaction.js @@ -9,12 +9,11 @@ const utils = require('./utils'); const sjclcodec = require('sjcl-codec'); const Amount = require('./amount').Amount; const Currency = require('./currency').Currency; -const UInt160 = require('./uint160').UInt160; const SerializedObject = require('./serializedobject').SerializedObject; const RippleError = require('./rippleerror').RippleError; const hashprefixes = require('./hashprefixes'); const log = require('./log').internal.sub('transaction'); -const {isValidAddress} = require('ripple-address-codec'); +const {isValidAddress, decodeAddress} = require('ripple-address-codec'); /** * @constructor Transaction @@ -470,7 +469,7 @@ Transaction.prototype.multiSigningData = function(account) { const so = new SerializedObject(); so.append(hashprefixes.HASH_TX_MULTISIGN_BYTES); so.parse_json(this.tx_json); - so.append(UInt160.from_json(account).to_bytes()); + so.append(decodeAddress(account)); return so; }; @@ -692,14 +691,10 @@ Transaction.prototype.sourceTag = function(tag) { }; Transaction.prototype._setAccount = function(name, value) { - const uInt160 = UInt160.from_json(value); - - if (!uInt160.is_valid()) { + if (!isValidAddress(value)) { throw new Error(name + ' must be a valid account'); } - - this.tx_json[name] = uInt160.to_json(); - + this.tx_json[name] = value; return this; }; @@ -1176,11 +1171,11 @@ Transaction._rewritePath = function(path) { const newNode = { }; if (node.hasOwnProperty('account')) { - newNode.account = UInt160.json_rewrite(node.account); + newNode.account = node.account; } if (node.hasOwnProperty('issuer')) { - newNode.issuer = UInt160.json_rewrite(node.issuer); + newNode.issuer = node.issuer; } if (node.hasOwnProperty('currency')) { @@ -1384,7 +1379,7 @@ Transaction.prototype.offerCancel = function(options_) { Transaction._prepareSignerEntry = function(signer) { const {account, weight} = signer; - assert(UInt160.is_valid(account), 'Signer account invalid'); + assert(isValidAddress(account), 'Signer account invalid'); assert(_.isNumber(weight), 'Signer weight missing'); assert(weight > 0 && weight <= 65535, 'Signer weight must be 1-65535'); @@ -1606,7 +1601,7 @@ Transaction.prototype.setSigners = function(signers) { }; Transaction.prototype.addMultiSigner = function(signer) { - assert(UInt160.is_valid(signer.Account), 'Signer must have a valid Account'); + assert(isValidAddress(signer.Account), 'Signer must have a valid Account'); if (_.isUndefined(this.tx_json.Signers)) { this.tx_json.Signers = []; @@ -1615,8 +1610,8 @@ Transaction.prototype.addMultiSigner = function(signer) { this.tx_json.Signers.push({Signer: signer}); this.tx_json.Signers.sort((a, b) => { - return UInt160.from_json(a.Signer.Account) - .cmp(UInt160.from_json(b.Signer.Account)); + return (new Buffer(decodeAddress(a.Signer.Account))).compare( + new Buffer(decodeAddress(b.Signer.Account))); }); return this; diff --git a/test/amount-test.js b/test/amount-test.js index 49753b17..265988c0 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -2,8 +2,6 @@ 'use strict'; const assert = require('assert'); const Amount = require('ripple-lib').Amount; -const UInt160 = require('ripple-lib').UInt160; - describe('Amount', function() { describe('Negatives', function() { @@ -292,26 +290,6 @@ describe('Amount', function() { assert.strictEqual('1', Amount.json_rewrite(1)); }); }); - describe('UInt160', function() { - it('Parse 0 export', function() { - assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json()); - }); - it('Parse 1', function() { - assert.deepEqual(UInt160.ACCOUNT_ONE, UInt160.from_generic('1').set_version(0).to_json()); - }); - it('Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export', function() { - assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json()); - }); - it('Parse rrrrrrrrrrrrrrrrrrrrBZbvji export', function() { - assert.strictEqual(UInt160.ACCOUNT_ONE, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrBZbvji').to_json()); - }); - it('is_valid rrrrrrrrrrrrrrrrrrrrrhoLvTp', function() { - assert(UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvTp')); - }); - it('!is_valid rrrrrrrrrrrrrrrrrrrrrhoLvT', function() { - assert(!UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvT')); - }); - }); describe('Amount validity', function() { it('is_valid 1', function() { assert(Amount.is_valid(1)); diff --git a/test/fixtures/schemas/ledgerhash.json b/test/fixtures/schemas/ledgerhash.json index bc67b99d..ac7dfe04 100644 --- a/test/fixtures/schemas/ledgerhash.json +++ b/test/fixtures/schemas/ledgerhash.json @@ -3,5 +3,5 @@ "title": "ledgerhash", "description": "A ledger hash", "type": "string", - "format": "ledgerHash" + "pattern": "^[A-F0-9]{64}$" } diff --git a/test/remote-test.js b/test/remote-test.js index f44c91e2..4f1d4ad0 100644 --- a/test/remote-test.js +++ b/test/remote-test.js @@ -4,15 +4,14 @@ const assert = require('assert-diff'); const lodash = require('lodash'); -const ripple = require('ripple-lib'); const Remote = require('ripple-lib').Remote; const Server = require('ripple-lib').Server; const Transaction = require('ripple-lib').Transaction; -const UInt160 = require('ripple-lib').UInt160; const Currency = require('ripple-lib').Currency; const Amount = require('ripple-lib').Amount; const PathFind = require('ripple-lib')._test.PathFind; const Log = require('ripple-lib')._test.Log; +const ACCOUNT_ONE = require('ripple-lib')._test.constants.ACCOUNT_ONE; let options; let remote; @@ -30,7 +29,7 @@ const TX_JSON = { Flags: 0, TransactionType: 'Payment', Account: ADDRESS, - Destination: ripple.UInt160.ACCOUNT_ONE, + Destination: ACCOUNT_ONE, Amount: { value: '1', currency: 'USD', @@ -1492,7 +1491,7 @@ describe('Remote', function() { it('Construct account_tx request', function() { let request = remote.requestAccountTransactions({ - account: UInt160.ACCOUNT_ONE, + account: ACCOUNT_ONE, ledger_index_min: -1, ledger_index_max: -1, limit: 5, @@ -1503,7 +1502,7 @@ describe('Remote', function() { assert.deepEqual(request.message, { command: 'account_tx', id: undefined, - account: UInt160.ACCOUNT_ONE, + account: ACCOUNT_ONE, ledger_index_min: -1, ledger_index_max: -1, binary: true, @@ -1513,14 +1512,14 @@ describe('Remote', function() { }); request = remote.requestAccountTransactions({ - account: UInt160.ACCOUNT_ONE, + account: ACCOUNT_ONE, min_ledger: -1, max_ledger: -1 }); assert.deepEqual(request.message, { command: 'account_tx', id: undefined, - account: UInt160.ACCOUNT_ONE, + account: ACCOUNT_ONE, binary: true, ledger_index_min: -1, ledger_index_max: -1 @@ -1528,7 +1527,7 @@ describe('Remote', function() { }); it('Construct account_tx request -- no binary', function() { const request = remote.requestAccountTransactions({ - account: UInt160.ACCOUNT_ONE, + account: ACCOUNT_ONE, ledger_index_min: -1, ledger_index_max: -1, limit: 5, @@ -1540,7 +1539,7 @@ describe('Remote', function() { assert.deepEqual(request.message, { command: 'account_tx', id: undefined, - account: UInt160.ACCOUNT_ONE, + account: ACCOUNT_ONE, ledger_index_min: -1, ledger_index_max: -1, binary: false, @@ -1618,7 +1617,7 @@ describe('Remote', function() { taker_pays: { currency: Currency.from_human('XRP').to_hex() }, - taker: UInt160.ACCOUNT_ONE + taker: ACCOUNT_ONE }); }); @@ -1645,7 +1644,7 @@ describe('Remote', function() { taker_pays: { currency: Currency.from_human('XRP').to_hex() }, - taker: UInt160.ACCOUNT_ONE, + taker: ACCOUNT_ONE, ledger_hash: LEDGER_HASH, limit: 10 }); diff --git a/test/transaction-test.js b/test/transaction-test.js index 5f9c516a..50b90fcc 100644 --- a/test/transaction-test.js +++ b/test/transaction-test.js @@ -10,6 +10,7 @@ const Transaction = require('ripple-lib').Transaction; const TransactionQueue = require('ripple-lib').TransactionQueue; const Remote = require('ripple-lib').Remote; const Server = require('ripple-lib').Server; +const {decodeAddress} = require('ripple-address-codec'); const transactionResult = { engine_result: 'tesSUCCESS', @@ -2257,7 +2258,7 @@ describe('Transaction', function() { const tbytes = ripple.SerializedObject.from_json( lodash.merge(transaction.tx_json, {SigningPubKey: ''})).buffer; - const abytes = ripple.UInt160.from_json(a1).to_bytes(); + const abytes = decodeAddress(a1); const prefix = require('ripple-lib')._test.HashPrefixes.HASH_TX_MULTISIGN_BYTES; assert.deepEqual(d1.buffer, prefix.concat(tbytes, abytes)); diff --git a/test/uint-test.js b/test/uint-test.js index 93afe2a2..fd4a8068 100644 --- a/test/uint-test.js +++ b/test/uint-test.js @@ -4,8 +4,9 @@ const _ = require('lodash'); const assert = require('assert-diff'); const lodash = require('lodash'); -const ripple = require('ripple-lib'); +const ripple = require('ripple-lib')._test; const fixtures = require('./fixtures/uint'); +const UInt160 = ripple.UInt160; function resultError(test, result) { function type(e) { @@ -101,4 +102,25 @@ function makeTests(uIntType) { }); } +describe('UInt160', function() { + it('Parse 0 export', function() { + assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json()); + }); + it('Parse 1', function() { + assert.deepEqual(UInt160.ACCOUNT_ONE, UInt160.from_generic('1').set_version(0).to_json()); + }); + it('Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export', function() { + assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json()); + }); + it('Parse rrrrrrrrrrrrrrrrrrrrBZbvji export', function() { + assert.strictEqual(UInt160.ACCOUNT_ONE, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrBZbvji').to_json()); + }); + it('is_valid rrrrrrrrrrrrrrrrrrrrrhoLvTp', function() { + assert(UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvTp')); + }); + it('!is_valid rrrrrrrrrrrrrrrrrrrrrhoLvT', function() { + assert(!UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvT')); + }); +}); + ['UInt128', 'UInt160', 'UInt256'].forEach(makeTests);