Merge pull request #566 from clark800/refactor

Decouple UInt160 from account.js and amount.js
This commit is contained in:
Chris Clark
2015-09-28 14:15:50 -07:00
10 changed files with 167 additions and 122 deletions

56
npm-shrinkwrap.json generated
View File

@@ -9,8 +9,8 @@
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
},
"babel-runtime": {
"version": "5.8.24",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.24.tgz",
"version": "5.8.25",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.25.tgz",
"dependencies": {
"core-js": {
"version": "1.1.4",
@@ -117,12 +117,12 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.2.tgz"
},
"ripple-address-codec": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-1.6.0.tgz",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-2.0.1.tgz",
"dependencies": {
"x-address-codec": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.6.0.tgz",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.7.0.tgz",
"dependencies": {
"base-x": {
"version": "1.0.1",
@@ -149,6 +149,22 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
}
}
},
"ripple-address-codec": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-1.6.0.tgz",
"dependencies": {
"x-address-codec": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/x-address-codec/-/x-address-codec-0.6.0.tgz",
"dependencies": {
"base-x": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-1.0.1.tgz"
}
}
}
}
}
}
},
@@ -168,6 +184,20 @@
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-0.7.2.tgz",
"dependencies": {
"bufferutil": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.1.0.tgz",
"dependencies": {
"bindings": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
},
"nan": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/nan/-/nan-1.8.4.tgz"
}
}
},
"options": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
@@ -175,6 +205,20 @@
"ultron": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz"
},
"utf-8-validate": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.1.0.tgz",
"dependencies": {
"bindings": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
},
"nan": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/nan/-/nan-1.8.4.tgz"
}
}
}
}
}

View File

@@ -26,7 +26,7 @@
"is-my-json-valid": "^2.12.2",
"lodash": "^3.1.0",
"lru-cache": "~2.5.0",
"ripple-address-codec": "^1.6.0",
"ripple-address-codec": "^2.0.1",
"ripple-keypairs": "^0.9.0",
"ripple-lib-transactionparser": "^0.5.1",
"ripple-lib-value": "0.1.0",

View File

@@ -17,7 +17,7 @@ const util = require('util');
const {deriveAddress} = require('ripple-keypairs');
const {EventEmitter} = require('events');
const {TransactionManager} = require('./transactionmanager');
const {UInt160} = require('./uint160');
const {isValidAddress} = require('ripple-address-codec');
/**
* @constructor Account
@@ -25,14 +25,13 @@ const {UInt160} = require('./uint160');
* @param {String} account
*/
function Account(remote, account) {
function Account(remote, address) {
EventEmitter.call(this);
const self = this;
this._remote = remote;
this._account = UInt160.from_json(account);
this._account_id = this._account.to_json();
this._address = address;
this._subs = 0;
// Ledger entry object
@@ -43,7 +42,7 @@ function Account(remote, account) {
if (_.includes(Account.subscribeEvents, type)) {
if (!self._subs && self._remote._connected) {
self._remote.requestSubscribe()
.addAccount(self._account_id)
.addAccount(self._address)
.broadcast().request();
}
self._subs += 1;
@@ -57,7 +56,7 @@ function Account(remote, account) {
self._subs -= 1;
if (!self._subs && self._remote._connected) {
self._remote.requestUnsubscribe()
.addAccount(self._account_id)
.addAccount(self._address)
.broadcast().request();
}
}
@@ -66,8 +65,8 @@ function Account(remote, account) {
this.on('removeListener', listenerRemoved);
function attachAccount(request) {
if (self._account.is_valid() && self._subs) {
request.addAccount(self._account_id);
if (isValidAddress(self._address) && self._subs) {
request.addAccount(self._address);
}
}
@@ -81,7 +80,7 @@ function Account(remote, account) {
let changed = false;
transaction.mmeta.each(function(an) {
const isAccount = an.fields.Account === self._account_id;
const isAccount = an.fields.Account === self._address;
const isAccountRoot = isAccount && (an.entryType === 'AccountRoot');
if (isAccountRoot) {
@@ -111,7 +110,7 @@ util.inherits(Account, EventEmitter);
Account.subscribeEvents = ['transaction', 'entry'];
Account.prototype.toJson = function() {
return this._account.to_json();
return this._address;
};
/**
@@ -121,7 +120,7 @@ Account.prototype.toJson = function() {
*/
Account.prototype.isValid = function() {
return this._account.is_valid();
return isValidAddress(this._address);
};
/**
@@ -131,7 +130,7 @@ Account.prototype.isValid = function() {
*/
Account.prototype.getInfo = function(callback) {
return this._remote.requestAccountInfo({account: this._account_id}, callback);
return this._remote.requestAccountInfo({account: this._address}, callback);
};
/**
@@ -210,7 +209,7 @@ Account.prototype.lines = function(callback_) {
}
}
this._remote.requestAccountLines({account: this._account_id}, accountLines);
this._remote.requestAccountLines({account: this._address}, accountLines);
return this;
};
@@ -275,7 +274,7 @@ Account.prototype.notifyTx = function(transaction) {
return;
}
const isThisAccount = (account === this._account_id);
const isThisAccount = (account === this._address);
this.emit(isThisAccount ? 'transaction-outbound' : 'transaction-inbound',
transaction);
@@ -331,7 +330,7 @@ Account.prototype.publicKeyIsActive = function(public_key, callback) {
// Catch the case of unfunded accounts
if (!account_info_res) {
if (public_key_as_uint160 === self._account_id) {
if (public_key_as_uint160 === self._address) {
async_callback(null, true);
} else {
async_callback(null, false);
@@ -373,20 +372,17 @@ Account.prototype.publicKeyIsActive = function(public_key, callback) {
* @returns {RippleAddress} Ripple Address
*/
Account._publicKeyToAddress = function(public_key) {
// Based on functions in /src/js/ripple/keypair.js
function hexToUInt160(publicKey) {
return deriveAddress(publicKey);
}
if (UInt160.is_valid(public_key)) {
if (isValidAddress(public_key)) {
return public_key;
} else if (/^[0-9a-fA-F]+$/.test(public_key)) {
return hexToUInt160(public_key);
return deriveAddress(public_key);
} else { // eslint-disable-line no-else-return
throw new Error('Public key is invalid. Must be a UInt160 or a hex string');
}
};
exports.Account = Account;
module.exports = {
Account
};
// vim:sw=2:sts=2:ts=8:et

View File

@@ -6,9 +6,10 @@
const assert = require('assert');
const extend = require('extend');
const utils = require('./utils');
const UInt160 = require('./uint160').UInt160;
const Currency = require('./currency').Currency;
const {XRPValue, IOUValue} = require('ripple-lib-value');
const {isValidAddress} = require('ripple-address-codec');
const {ACCOUNT_ONE, ACCOUNT_ZERO} = require('./constants');
type Value = XRPValue | IOUValue;
@@ -21,7 +22,7 @@ function Amount(value = new XRPValue(NaN)) {
this._value = value;
this._is_native = true; // Default to XRP. Only valid if value is not NaN.
this._currency = new Currency();
this._issuer = new UInt160();
this._issuer = 'NaN';
}
/**
@@ -105,7 +106,7 @@ Amount.NaN = function() {
};
Amount.from_components_unsafe = function(value: Value, currency: Currency,
issuer: UInt160, isNative: boolean
issuer: string, isNative: boolean
) {
const result = new Amount(value);
result._is_native = isNative;
@@ -402,7 +403,7 @@ Amount.prototype.equals = function(d, ignore_issuer) {
&& this._is_native === d._is_native
&& this._value.equals(d._value)
&& (this._is_native || (this._currency.equals(d._currency)
&& (ignore_issuer || this._issuer.equals(d._issuer))));
&& (ignore_issuer || this._issuer === d._issuer)));
};
// True if Amounts are valid and both native or non-native.
@@ -428,9 +429,8 @@ Amount.prototype.is_valid = function() {
};
Amount.prototype.is_valid_full = function() {
return this.is_valid()
&& this._currency.is_valid()
&& this._issuer.is_valid();
return this.is_valid() && this._currency.is_valid()
&& isValidAddress(this._issuer) && this._issuer !== ACCOUNT_ZERO;
};
Amount.prototype.is_zero = function() {
@@ -532,7 +532,7 @@ Amount.prototype.parse_human = function(j, options) {
};
Amount.prototype.parse_issuer = function(issuer) {
this._issuer = UInt160.from_json(issuer);
this._issuer = issuer;
return this;
};
@@ -583,7 +583,7 @@ function(quality, counterCurrency, counterIssuer, opts) {
const offset = parseInt(offset_hex, 16) - 100;
this._currency = Currency.from_json(counterCurrency);
this._issuer = UInt160.from_json(counterIssuer);
this._issuer = counterIssuer;
this._is_native = this._currency.is_native();
if (this._is_native && baseCurrency.is_native()) {
@@ -643,7 +643,7 @@ function(quality, counterCurrency, counterIssuer, opts) {
Amount.prototype.parse_number = function(n) {
this._is_native = false;
this._currency = Currency.from_json(1);
this._issuer = UInt160.from_json(1);
this._issuer = ACCOUNT_ONE;
this._set_value(new IOUValue(n));
return this;
};
@@ -659,15 +659,15 @@ Amount.prototype.parse_json = function(j) {
if (m) {
this._currency = Currency.from_json(m[2]);
if (m[3]) {
this._issuer = UInt160.from_json(m[3]);
this._issuer = m[3];
} else {
this._issuer = UInt160.from_json('1');
this._issuer = 'NaN';
}
this.parse_value(m[1]);
} else {
this.parse_native(j);
this._currency = Currency.from_json('0');
this._issuer = UInt160.from_json('0');
this._issuer = ACCOUNT_ZERO;
}
break;
@@ -686,9 +686,10 @@ Amount.prototype.parse_json = function(j) {
// Parse the passed value to sanitize and copy it.
this._currency.parse_json(j.currency, true); // Never XRP.
if (typeof j.issuer === 'string') {
this._issuer.parse_json(j.issuer);
if (typeof j.issuer !== 'string') {
throw new Error('issuer must be a string');
}
this._issuer = j.issuer;
this.parse_value(j.value);
}
@@ -736,12 +737,7 @@ Amount.prototype.set_currency = function(c) {
};
Amount.prototype.set_issuer = function(issuer) {
if (issuer instanceof UInt160) {
this._issuer = issuer;
} else {
this._issuer = UInt160.from_json(issuer);
}
this._issuer = issuer;
return this;
};
@@ -939,7 +935,7 @@ Amount.prototype.to_human_full = function(options) {
const opts = options || {};
const value = this.to_human(opts);
const currency = this._currency.to_human();
const issuer = this._issuer.to_json(opts);
const issuer = this._issuer;
const base = value + '/' + currency;
return this.is_native() ? base : (base + '/' + issuer);
};
@@ -955,21 +951,21 @@ Amount.prototype.to_json = function() {
this._currency.to_hex() : this._currency.to_json()
};
if (this._issuer.is_valid()) {
amount_json.issuer = this._issuer.to_json();
if (isValidAddress(this._issuer)) {
amount_json.issuer = this._issuer;
}
return amount_json;
};
Amount.prototype.to_text_full = function(opts) {
Amount.prototype.to_text_full = function() {
if (!this.is_valid()) {
return 'NaN';
}
return this._is_native
? this.to_human() + '/XRP'
: this.to_text() + '/' + this._currency.to_json()
+ '/' + this._issuer.to_json(opts);
+ '/' + this._issuer;
};
// For debugging.
@@ -998,11 +994,8 @@ Amount.prototype.not_equals_why = function(d, ignore_issuer) {
if (!this._currency.equals(d._currency)) {
return 'Non-XRP currency differs.';
}
if (!ignore_issuer && !this._issuer.equals(d._issuer)) {
return 'Non-XRP issuer differs: '
+ d._issuer.to_json()
+ '/'
+ this._issuer.to_json();
if (!ignore_issuer && this._issuer !== d._issuer) {
return 'Non-XRP issuer differs: ' + d._issuer + '/' + this._issuer;
}
}
};

6
src/core/constants.js Normal file
View File

@@ -0,0 +1,6 @@
'use strict';
module.exports = {
ACCOUNT_ZERO: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
ACCOUNT_ONE: 'rrrrrrrrrrrrrrrrrrrrBZbvji'
};

View File

@@ -1,7 +1,10 @@
var extend = require('extend');
var utils = require('./utils');
var UInt160 = require('./uint160').UInt160;
var Amount = require('./amount').Amount;
'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');
/**
* Meta data processing facility
@@ -11,8 +14,6 @@ var Amount = require('./amount').Amount;
*/
function Meta(data) {
var self = this;
this.nodes = [ ];
if (typeof data !== 'object') {
@@ -24,7 +25,7 @@ function Meta(data) {
}
data.AffectedNodes.forEach(this.addNode, this);
};
}
Meta.NODE_TYPES = [
'CreatedNode',
@@ -53,10 +54,10 @@ Meta.ACCOUNT_FIELDS = [
*/
Meta.prototype.getNodeType = function(node) {
var result = null;
let result = null;
for (var i=0; i<Meta.NODE_TYPES.length; i++) {
var type = Meta.NODE_TYPES[i];
for (let i = 0; i < Meta.NODE_TYPES.length; i++) {
const type = Meta.NODE_TYPES[i];
if (node.hasOwnProperty(type)) {
result = type;
break;
@@ -83,20 +84,22 @@ Meta.prototype.isAccountField = function(field) {
*/
Meta.prototype.addNode = function(node) {
this._affectedAccounts = void(0);
this._affectedBooks = void(0);
this._affectedAccounts = undefined;
this._affectedBooks = undefined;
var result = { };
const result = { };
if ((result.nodeType = this.getNodeType(node))) {
node = node[result.nodeType];
result.diffType = result.nodeType;
result.entryType = node.LedgerEntryType;
result.ledgerIndex = node.LedgerIndex;
result.fields = extend({ }, node.PreviousFields, node.NewFields, node.FinalFields);
result.fieldsPrev = node.PreviousFields || { };
result.fieldsNew = node.NewFields || { };
result.fieldsFinal = node.FinalFields || { };
result.nodeType = this.getNodeType(node);
if (result.nodeType) {
const _node = node[result.nodeType];
result.diffType = result.nodeType;
result.entryType = _node.LedgerEntryType;
result.ledgerIndex = _node.LedgerIndex;
result.fields = extend({ }, _node.PreviousFields,
_node.NewFields, _node.FinalFields);
result.fieldsPrev = _node.PreviousFields || { };
result.fieldsNew = _node.NewFields || { };
result.fieldsFinal = _node.FinalFields || { };
// getAffectedBooks will set this
// result.bookKey = undefined;
@@ -126,36 +129,36 @@ Meta.prototype.getNodes = function(options) {
}
return true;
});
} else {
return this.nodes;
}
return this.nodes;
};
Meta.prototype.getAffectedAccounts = function(from) {
Meta.prototype.getAffectedAccounts = function() {
if (this._affectedAccounts) {
return this._affectedAccounts;
}
var accounts = [ ];
const accounts = [ ];
// This code should match the behavior of the C++ method:
// TransactionMetaSet::getAffectedAccounts
for (var i=0; i<this.nodes.length; i++) {
var node = this.nodes[i];
var fields = (node.nodeType === 'CreatedNode')
for (let i = 0; i < this.nodes.length; i++) {
const node = this.nodes[i];
const fields = (node.nodeType === 'CreatedNode')
? node.fieldsNew
: node.fieldsFinal;
for (var fieldName in fields) {
var field = fields[fieldName];
for (const fieldName in fields) {
const field = fields[fieldName];
if (this.isAccountField(fieldName) && UInt160.is_valid(field)) {
accounts.push(field);
} else if (~Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName)) {
var amount = Amount.from_json(field);
var issuer = amount.issuer();
if (issuer.is_valid() && !issuer.is_zero()) {
accounts.push(issuer.to_json());
} else if (
Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName) !== -1) {
const amount = Amount.from_json(field);
const issuer = amount.issuer();
if (isValidAddress(issuer) && issuer !== ACCOUNT_ZERO) {
accounts.push(issuer);
}
}
}
@@ -171,29 +174,29 @@ Meta.prototype.getAffectedBooks = function() {
return this._affectedBooks;
}
var books = [ ];
const books = [ ];
for (var i=0; i<this.nodes.length; i++) {
var node = this.nodes[i];
for (let i = 0; i < this.nodes.length; i++) {
const node = this.nodes[i];
if (node.entryType !== 'Offer') {
continue;
}
var gets = Amount.from_json(node.fields.TakerGets);
var pays = Amount.from_json(node.fields.TakerPays);
var getsKey = gets.currency().to_json();
var paysKey = pays.currency().to_json();
const gets = Amount.from_json(node.fields.TakerGets);
const pays = Amount.from_json(node.fields.TakerPays);
let getsKey = gets.currency().to_json();
let paysKey = pays.currency().to_json();
if (getsKey !== 'XRP') {
getsKey += '/' + gets.issuer().to_json();
getsKey += '/' + gets.issuer();
}
if (paysKey !== 'XRP') {
paysKey += '/' + pays.issuer().to_json();
paysKey += '/' + pays.issuer();
}
var key = getsKey + ':' + paysKey;
const key = getsKey + ':' + paysKey;
// Hell of a lot of work, so we are going to cache this. We can use this
// later to good effect in OrderBook.notify to make sure we only process
@@ -243,12 +246,12 @@ Meta.prototype.getAffectedBooks = function() {
*/
[
'forEach',
'map',
'filter',
'every',
'some',
'reduce'
'forEach',
'map',
'filter',
'every',
'some',
'reduce'
].forEach(function(fn) {
Meta.prototype[fn] = function() {
return Array.prototype[fn].apply(this.nodes, arguments);

View File

@@ -29,8 +29,7 @@ function createAmount(value, currency_, counterparty_) {
Currency.from_json(currency_);
const counterparty = counterparty_ instanceof UInt160 ?
counterparty_ :
UInt160.from_json(counterparty_);
counterparty_.to_json() : counterparty_;
return Amount.from_components_unsafe(new IOUValue(value),
currency, counterparty, false);

View File

@@ -100,7 +100,8 @@ SerializedType.serialize_varint = function(so, val) {
SerializedType.prototype.parse_varint = function(so) {
const b1 = so.read(1)[0];
let b2, b3;
let b2;
let b3;
let result;
if (b1 > 254) {
@@ -416,7 +417,8 @@ exports.Quality = new SerializedType({
value = new BigNumber(val);
}
let hi = 0, lo = 0;
let hi = 0;
let lo = 0;
const offset = value.e - 15;
if (val !== 0) {
@@ -483,7 +485,8 @@ const STAmount = exports.Amount = new SerializedType({
valueBytes[0] |= 0x40;
}
} else {
let hi = 0, lo = 0;
let hi = 0;
let lo = 0;
// First bit: non-native
hi |= 1 << 31;
@@ -518,7 +521,7 @@ const STAmount = exports.Amount = new SerializedType({
STCurrency.serialize(so, currency, true);
// Issuer (160-bit hash)
so.append(amount.issuer().to_bytes());
so.append(UInt160.from_json(amount.issuer()).to_bytes());
}
},
parse: function(so) {
@@ -834,7 +837,7 @@ exports.STMemo = new SerializedType({
output.parsed_memo_data = convertHexToString(output.MemoData);
}
/* eslint-disable no-empty */
} catch(e) {
} catch (e) {
// empty
// we'll fail in case the content does not match what the MemoFormat
// described

View File

@@ -14,6 +14,7 @@ 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');
/**
* @constructor Transaction
@@ -722,7 +723,7 @@ Transaction.prototype._setAmount = function(name, amount, options_) {
if (!(isNative || parsedAmount.currency().is_valid())) {
throw new Error(name + ' must have a valid currency');
}
if (!(isNative || parsedAmount.issuer().is_valid())) {
if (!(isNative || isValidAddress(parsedAmount.issuer()))) {
throw new Error(name + ' must have a valid issuer');
}

View File

@@ -21,7 +21,7 @@ function TransactionManager(account) {
const self = this;
this._account = account;
this._accountID = account._account_id;
this._accountID = account._address;
this._remote = account._remote;
this._nextSequence = undefined;
this._maxFee = this._remote.max_fee;