mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-27 23:55:49 +00:00
Delete serialization code
This commit is contained in:
4
npm-shrinkwrap.json
generated
4
npm-shrinkwrap.json
generated
@@ -133,8 +133,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ripple-binary-codec": {
|
"ripple-binary-codec": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-0.0.6.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"lodash": "^3.1.0",
|
"lodash": "^3.1.0",
|
||||||
"lru-cache": "~2.5.0",
|
"lru-cache": "~2.5.0",
|
||||||
"ripple-address-codec": "^2.0.1",
|
"ripple-address-codec": "^2.0.1",
|
||||||
"ripple-binary-codec": "^0.0.5",
|
"ripple-binary-codec": "^0.0.6",
|
||||||
"ripple-keypairs": "^0.9.0",
|
"ripple-keypairs": "^0.9.0",
|
||||||
"ripple-lib-transactionparser": "^0.5.1",
|
"ripple-lib-transactionparser": "^0.5.1",
|
||||||
"ripple-lib-value": "0.1.0",
|
"ripple-lib-value": "0.1.0",
|
||||||
|
|||||||
@@ -67,15 +67,19 @@ function parseOutcome(tx: Object): ?Object {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hexToString(hex) {
|
||||||
|
return hex ? new Buffer(hex, 'hex').toString('utf-8') : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function parseMemos(tx: Object): ?Array<Object> {
|
function parseMemos(tx: Object): ?Array<Object> {
|
||||||
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
if (!Array.isArray(tx.Memos) || tx.Memos.length === 0) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return tx.Memos.map((m) => {
|
return tx.Memos.map((m) => {
|
||||||
return removeUndefined({
|
return removeUndefined({
|
||||||
type: m.Memo.parsed_memo_type,
|
type: m.Memo.parsed_memo_type || hexToString(m.Memo.MemoType),
|
||||||
format: m.Memo.parsed_memo_format,
|
format: m.Memo.parsed_memo_format || hexToString(m.Memo.MemoFormat),
|
||||||
data: m.Memo.parsed_memo_data
|
data: m.Memo.parsed_memo_data || hexToString(m.Memo.MemoData)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const BN = require('bn.js');
|
|
||||||
const extend = require('extend');
|
|
||||||
const {encode, decode} = require('ripple-address-codec');
|
|
||||||
|
|
||||||
const Base = {};
|
|
||||||
|
|
||||||
extend(Base, {
|
|
||||||
VER_NONE: 1,
|
|
||||||
VER_NODE_PUBLIC: 28,
|
|
||||||
VER_NODE_PRIVATE: 32,
|
|
||||||
VER_ACCOUNT_ID: 0,
|
|
||||||
VER_ACCOUNT_PUBLIC: 35,
|
|
||||||
VER_ACCOUNT_PRIVATE: 34,
|
|
||||||
VER_FAMILY_GENERATOR: 41,
|
|
||||||
VER_FAMILY_SEED: 33,
|
|
||||||
VER_ED25519_SEED: [0x01, 0xE1, 0x4B]
|
|
||||||
});
|
|
||||||
|
|
||||||
// --> input: big-endian array of bytes.
|
|
||||||
// <-- string at least as long as input.
|
|
||||||
Base.encode = function(input, alphabet) {
|
|
||||||
return encode(input, {alphabet});
|
|
||||||
};
|
|
||||||
|
|
||||||
// --> input: String
|
|
||||||
// <-- array of bytes or undefined.
|
|
||||||
Base.decode = function(input, alphabet) {
|
|
||||||
if (typeof input !== 'string') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return decode(input, {alphabet});
|
|
||||||
} catch (e) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// --> input: Array
|
|
||||||
// <-- String
|
|
||||||
Base.encode_check = function(version, input, alphabet) {
|
|
||||||
return encode(input, {version, alphabet});
|
|
||||||
};
|
|
||||||
|
|
||||||
// --> input : String
|
|
||||||
// <-- NaN || BN
|
|
||||||
Base.decode_check = function(version, input, alphabet) {
|
|
||||||
try {
|
|
||||||
const decoded = decode(input, {version, alphabet});
|
|
||||||
return new BN(decoded);
|
|
||||||
} catch (e) {
|
|
||||||
return NaN;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.Base = Base;
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
|
|
||||||
function normalize(digitArray) {
|
|
||||||
let i = 0;
|
|
||||||
while (digitArray[i] === 0) {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if (i > 0) {
|
|
||||||
digitArray.splice(0, i);
|
|
||||||
}
|
|
||||||
return digitArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function divmod(digitArray, base, divisor) {
|
|
||||||
let remainder = 0;
|
|
||||||
let temp;
|
|
||||||
let divided;
|
|
||||||
let j = -1;
|
|
||||||
|
|
||||||
const length = digitArray.length;
|
|
||||||
const quotient = new Array(length);
|
|
||||||
|
|
||||||
while (++j < length) {
|
|
||||||
temp = remainder * base + digitArray[j];
|
|
||||||
divided = temp / divisor;
|
|
||||||
quotient[j] = divided << 0;
|
|
||||||
remainder = temp % divisor;
|
|
||||||
}
|
|
||||||
return {quotient: normalize(quotient), remainder: remainder};
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertBase(digitArray, fromBase, toBase) {
|
|
||||||
const result = [];
|
|
||||||
let dividend = digitArray;
|
|
||||||
let qr;
|
|
||||||
while (dividend.length > 0) {
|
|
||||||
qr = divmod(dividend, fromBase, toBase);
|
|
||||||
result.unshift(qr.remainder);
|
|
||||||
dividend = qr.quotient;
|
|
||||||
}
|
|
||||||
return normalize(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = convertBase;
|
|
||||||
@@ -5,28 +5,19 @@ exports.Amount = require('./amount').Amount;
|
|||||||
exports.Account = require('./account').Account;
|
exports.Account = require('./account').Account;
|
||||||
exports.Transaction = require('./transaction').Transaction;
|
exports.Transaction = require('./transaction').Transaction;
|
||||||
exports.Currency = require('./currency').Currency;
|
exports.Currency = require('./currency').Currency;
|
||||||
exports.Base = require('./base').Base;
|
|
||||||
exports.Meta = require('./meta').Meta;
|
exports.Meta = require('./meta').Meta;
|
||||||
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
|
||||||
exports.RippleError = require('./rippleerror').RippleError;
|
exports.RippleError = require('./rippleerror').RippleError;
|
||||||
exports.binformat = require('./binformat');
|
|
||||||
exports.utils = require('./utils');
|
exports.utils = require('./utils');
|
||||||
exports.Server = require('./server').Server;
|
exports.Server = require('./server').Server;
|
||||||
exports.Ledger = require('./ledger').Ledger;
|
exports.Ledger = require('./ledger').Ledger;
|
||||||
exports.TransactionQueue = require('./transactionqueue').TransactionQueue;
|
|
||||||
exports.convertBase = require('./baseconverter');
|
|
||||||
|
|
||||||
exports._test = {
|
exports._test = {
|
||||||
Log: require('./log'),
|
Log: require('./log'),
|
||||||
PathFind: require('./pathfind').PathFind,
|
PathFind: require('./pathfind').PathFind,
|
||||||
TransactionManager: require('./transactionmanager').TransactionManager,
|
TransactionManager: require('./transactionmanager').TransactionManager,
|
||||||
|
TransactionQueue: require('./transactionqueue').TransactionQueue,
|
||||||
RangeSet: require('./rangeset').RangeSet,
|
RangeSet: require('./rangeset').RangeSet,
|
||||||
HashPrefixes: require('./hashprefixes'),
|
HashPrefixes: require('./hashprefixes'),
|
||||||
UInt128: require('./uint128').UInt128,
|
|
||||||
UInt160: require('./uint160').UInt160,
|
|
||||||
UInt256: require('./uint256').UInt256,
|
|
||||||
OrderbookUtils: require('./orderbookutils'),
|
OrderbookUtils: require('./orderbookutils'),
|
||||||
constants: require('./constants')
|
constants: require('./constants')
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.types = require('./serializedtypes');
|
|
||||||
|
|||||||
@@ -29,12 +29,11 @@ const Account = require('./account').Account;
|
|||||||
const Meta = require('./meta').Meta;
|
const Meta = require('./meta').Meta;
|
||||||
const OrderBook = require('./orderbook').OrderBook;
|
const OrderBook = require('./orderbook').OrderBook;
|
||||||
const PathFind = require('./pathfind').PathFind;
|
const PathFind = require('./pathfind').PathFind;
|
||||||
const SerializedObject = require('./serializedobject').SerializedObject;
|
|
||||||
const RippleError = require('./rippleerror').RippleError;
|
const RippleError = require('./rippleerror').RippleError;
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
const hashprefixes = require('./hashprefixes');
|
|
||||||
const log = require('./log').internal.sub('remote');
|
const log = require('./log').internal.sub('remote');
|
||||||
const {isValidAddress} = require('ripple-address-codec');
|
const {isValidAddress} = require('ripple-address-codec');
|
||||||
|
const binary = require('ripple-binary-codec');
|
||||||
|
|
||||||
export type GetLedgerSequenceCallback = (err?: ?Error, index?: number) => void;
|
export type GetLedgerSequenceCallback = (err?: ?Error, index?: number) => void;
|
||||||
|
|
||||||
@@ -1412,27 +1411,26 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Remote.parseBinaryAccountTransaction = function(transaction) {
|
Remote.parseBinaryAccountTransaction = function(transaction) {
|
||||||
const tx_obj = new SerializedObject(transaction.tx_blob);
|
const tx_json = binary.decode(transaction.tx_blob);
|
||||||
const tx_obj_json = tx_obj.to_json();
|
const meta = binary.decode(transaction.meta);
|
||||||
const meta = new SerializedObject(transaction.meta).to_json();
|
|
||||||
|
|
||||||
const tx_result = {
|
const tx_result = {
|
||||||
validated: transaction.validated
|
validated: transaction.validated
|
||||||
};
|
};
|
||||||
|
|
||||||
tx_result.meta = meta;
|
tx_result.meta = meta;
|
||||||
tx_result.tx = tx_obj_json;
|
tx_result.tx = tx_json;
|
||||||
tx_result.tx.hash = tx_obj.hash(hashprefixes.HASH_TX_ID).to_hex();
|
tx_result.tx.hash = Transaction.from_json(tx_json).hash();
|
||||||
tx_result.tx.ledger_index = transaction.ledger_index;
|
tx_result.tx.ledger_index = transaction.ledger_index;
|
||||||
tx_result.tx.inLedger = transaction.ledger_index;
|
tx_result.tx.inLedger = transaction.ledger_index;
|
||||||
|
|
||||||
if (typeof meta.DeliveredAmount === 'object') {
|
if (typeof meta.DeliveredAmount === 'object') {
|
||||||
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
||||||
} else {
|
} else {
|
||||||
switch (typeof tx_obj_json.Amount) {
|
switch (typeof tx_json.Amount) {
|
||||||
case 'string':
|
case 'string':
|
||||||
case 'object':
|
case 'object':
|
||||||
tx_result.meta.delivered_amount = tx_obj_json.Amount;
|
tx_result.meta.delivered_amount = tx_json.Amount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1441,10 +1439,10 @@ Remote.parseBinaryAccountTransaction = function(transaction) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Remote.parseBinaryTransaction = function(transaction) {
|
Remote.parseBinaryTransaction = function(transaction) {
|
||||||
const tx_obj = new SerializedObject(transaction.tx).to_json();
|
const tx_json = binary.decode(transaction.tx);
|
||||||
const meta = new SerializedObject(transaction.meta).to_json();
|
const meta = binary.decode(transaction.meta);
|
||||||
|
|
||||||
const tx_result = tx_obj;
|
const tx_result = tx_json;
|
||||||
|
|
||||||
tx_result.date = transaction.date;
|
tx_result.date = transaction.date;
|
||||||
tx_result.hash = transaction.hash;
|
tx_result.hash = transaction.hash;
|
||||||
@@ -1459,10 +1457,10 @@ Remote.parseBinaryTransaction = function(transaction) {
|
|||||||
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
switch (typeof tx_obj.Amount) {
|
switch (typeof tx_json.Amount) {
|
||||||
case 'string':
|
case 'string':
|
||||||
case 'object':
|
case 'object':
|
||||||
tx_result.meta.delivered_amount = tx_obj.Amount;
|
tx_result.meta.delivered_amount = tx_json.Amount;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1481,7 +1479,7 @@ Remote.parseBinaryTransaction = function(transaction) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Remote.parseBinaryLedgerData = function(ledgerData) {
|
Remote.parseBinaryLedgerData = function(ledgerData) {
|
||||||
const data = new SerializedObject(ledgerData.data).to_json();
|
const data = binary.decode(ledgerData.data);
|
||||||
data.index = ledgerData.index;
|
data.index = ledgerData.index;
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,369 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const extend = require('extend');
|
|
||||||
const BN = require('bn.js');
|
|
||||||
const hashjs = require('hash.js');
|
|
||||||
const sjclcodec = require('sjcl-codec');
|
|
||||||
const binformat = require('./binformat');
|
|
||||||
const stypes = require('./serializedtypes');
|
|
||||||
const utils = require('./utils');
|
|
||||||
const UInt256 = require('./uint256').UInt256;
|
|
||||||
|
|
||||||
const TRANSACTION_TYPES = { };
|
|
||||||
|
|
||||||
Object.keys(binformat.tx).forEach(function(key) {
|
|
||||||
TRANSACTION_TYPES[binformat.tx[key][0]] = key;
|
|
||||||
});
|
|
||||||
|
|
||||||
const LEDGER_ENTRY_TYPES = {};
|
|
||||||
|
|
||||||
Object.keys(binformat.ledger).forEach(function(key) {
|
|
||||||
LEDGER_ENTRY_TYPES[binformat.ledger[key][0]] = key;
|
|
||||||
});
|
|
||||||
|
|
||||||
const TRANSACTION_RESULTS = {};
|
|
||||||
|
|
||||||
Object.keys(binformat.ter).forEach(function(key) {
|
|
||||||
TRANSACTION_RESULTS[binformat.ter[key]] = key;
|
|
||||||
});
|
|
||||||
|
|
||||||
function fieldType(fieldName) {
|
|
||||||
const fieldDef = binformat.fieldsInverseMap[fieldName];
|
|
||||||
return binformat.types[fieldDef[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
function SerializedObject(buf) {
|
|
||||||
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf))) {
|
|
||||||
this.buffer = buf;
|
|
||||||
} else if (typeof buf === 'string') {
|
|
||||||
this.buffer = sjclcodec.bytes.fromBits(sjclcodec.hex.toBits(buf));
|
|
||||||
} else if (!buf) {
|
|
||||||
this.buffer = [];
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid buffer passed.');
|
|
||||||
}
|
|
||||||
this.pointer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializedObject.from_json = function(obj) {
|
|
||||||
const so = new SerializedObject();
|
|
||||||
so.parse_json(obj);
|
|
||||||
return so;
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.check_fields = function(typedef, obj) {
|
|
||||||
const missingFields = [];
|
|
||||||
const unknownFields = [];
|
|
||||||
const fieldsMap = {};
|
|
||||||
|
|
||||||
// Get missing required fields
|
|
||||||
typedef.forEach(function(field) {
|
|
||||||
const fieldName = field[0];
|
|
||||||
const isRequired = field[1] === binformat.REQUIRED;
|
|
||||||
|
|
||||||
if (isRequired && obj[fieldName] === undefined) {
|
|
||||||
missingFields.push(fieldName);
|
|
||||||
} else {
|
|
||||||
fieldsMap[fieldName] = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get fields that are not specified in format
|
|
||||||
Object.keys(obj).forEach(function(key) {
|
|
||||||
if (!fieldsMap[key] && /^[A-Z]/.test(key)) {
|
|
||||||
unknownFields.push(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!(missingFields.length || unknownFields.length)) {
|
|
||||||
// No missing or unknown fields
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let errorMessage;
|
|
||||||
|
|
||||||
if (obj.TransactionType !== undefined) {
|
|
||||||
errorMessage = SerializedObject.lookup_type_tx(obj.TransactionType);
|
|
||||||
} else if (obj.LedgerEntryType !== undefined) {
|
|
||||||
errorMessage = SerializedObject.lookup_type_le(obj.LedgerEntryType);
|
|
||||||
} else {
|
|
||||||
errorMessage = 'TransactionMetaData';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missingFields.length > 0) {
|
|
||||||
errorMessage += ' is missing fields: ' + JSON.stringify(missingFields);
|
|
||||||
}
|
|
||||||
if (unknownFields.length > 0) {
|
|
||||||
errorMessage += (missingFields.length ? ' and' : '')
|
|
||||||
+ ' has unknown fields: ' + JSON.stringify(unknownFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(errorMessage);
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.parse_json = function(obj_) {
|
|
||||||
// Create a copy of the object so we don't modify it
|
|
||||||
const obj = extend(true, {}, obj_);
|
|
||||||
let typedef;
|
|
||||||
|
|
||||||
if (typeof obj.TransactionType === 'number') {
|
|
||||||
obj.TransactionType = SerializedObject.lookup_type_tx(obj.TransactionType);
|
|
||||||
if (!obj.TransactionType) {
|
|
||||||
throw new Error('Transaction type ID is invalid.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof obj.LedgerEntryType === 'number') {
|
|
||||||
obj.LedgerEntryType = SerializedObject.lookup_type_le(obj.LedgerEntryType);
|
|
||||||
|
|
||||||
if (!obj.LedgerEntryType) {
|
|
||||||
throw new Error('LedgerEntryType ID is invalid.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof obj.TransactionType === 'string') {
|
|
||||||
typedef = binformat.tx[obj.TransactionType];
|
|
||||||
if (!Array.isArray(typedef)) {
|
|
||||||
throw new Error('Transaction type is invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef = typedef.slice();
|
|
||||||
obj.TransactionType = typedef.shift();
|
|
||||||
} else if (typeof obj.LedgerEntryType === 'string') {
|
|
||||||
typedef = binformat.ledger[obj.LedgerEntryType];
|
|
||||||
|
|
||||||
if (!Array.isArray(typedef)) {
|
|
||||||
throw new Error('LedgerEntryType is invalid');
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef = typedef.slice();
|
|
||||||
obj.LedgerEntryType = typedef.shift();
|
|
||||||
|
|
||||||
} else if (typeof obj.AffectedNodes === 'object') {
|
|
||||||
typedef = binformat.metadata;
|
|
||||||
} else {
|
|
||||||
throw new Error('Object to be serialized must contain either' +
|
|
||||||
' TransactionType, LedgerEntryType or AffectedNodes.');
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializedObject.check_fields(typedef, obj);
|
|
||||||
this.serialize(typedef, obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.append = function(bytes_) {
|
|
||||||
const bytes = bytes_ instanceof SerializedObject ? bytes_.buffer : bytes_;
|
|
||||||
|
|
||||||
// Make sure both buffer and bytes are Array. Either could be a Buffer.
|
|
||||||
if (Array.isArray(this.buffer) && Array.isArray(bytes)) {
|
|
||||||
// `this.buffer = this.buffer.concat(bytes)` can be unbearably slow for
|
|
||||||
// large bytes length and acceptable bytes length is limited for
|
|
||||||
// `Array.prototype.push.apply(this.buffer, bytes)` as every element in the
|
|
||||||
// bytes array is pushed onto the stack, potentially causing a RangeError
|
|
||||||
// exception. Both of these solutions are known to be problematic for
|
|
||||||
// ledger 7501326. KISS instead
|
|
||||||
|
|
||||||
for (let i = 0; i < bytes.length; i++) {
|
|
||||||
this.buffer.push(bytes[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.buffer = this.buffer.concat(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pointer += bytes.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.resetPointer = function() {
|
|
||||||
this.pointer = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
function readOrPeek(advance) {
|
|
||||||
return function(bytes) {
|
|
||||||
const start = this.pointer;
|
|
||||||
const end = start + bytes;
|
|
||||||
|
|
||||||
if (end > this.buffer.length) {
|
|
||||||
throw new Error('Buffer length exceeded');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = this.buffer.slice(start, end);
|
|
||||||
|
|
||||||
if (advance) {
|
|
||||||
this.pointer = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializedObject.prototype.read = readOrPeek(true);
|
|
||||||
|
|
||||||
SerializedObject.prototype.peek = readOrPeek(false);
|
|
||||||
|
|
||||||
SerializedObject.prototype.to_bits = function() {
|
|
||||||
return sjclcodec.bytes.toBits(this.buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.to_hex = function() {
|
|
||||||
return sjclcodec.hex.fromBits(this.to_bits()).toUpperCase();
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.to_json = function() {
|
|
||||||
const old_pointer = this.pointer;
|
|
||||||
|
|
||||||
this.resetPointer();
|
|
||||||
|
|
||||||
const output = { };
|
|
||||||
|
|
||||||
while (this.pointer < this.buffer.length) {
|
|
||||||
const key_and_value = stypes.parse(this);
|
|
||||||
const key = key_and_value[0];
|
|
||||||
const value = key_and_value[1];
|
|
||||||
output[key] = SerializedObject.jsonify_structure(value, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pointer = old_pointer;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.jsonify_structure = function(structure, fieldName) {
|
|
||||||
let output;
|
|
||||||
|
|
||||||
switch (typeof structure) {
|
|
||||||
case 'number':
|
|
||||||
switch (fieldName) {
|
|
||||||
case 'LedgerEntryType':
|
|
||||||
output = LEDGER_ENTRY_TYPES[structure];
|
|
||||||
break;
|
|
||||||
case 'TransactionResult':
|
|
||||||
output = TRANSACTION_RESULTS[structure];
|
|
||||||
break;
|
|
||||||
case 'TransactionType':
|
|
||||||
output = TRANSACTION_TYPES[structure];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output = structure;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'object':
|
|
||||||
if (structure === null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof structure.to_json === 'function') {
|
|
||||||
output = structure.to_json();
|
|
||||||
} else if (structure instanceof BN) {
|
|
||||||
// We assume that any BN is a UInt64 field
|
|
||||||
assert.equal(fieldType(fieldName), 'Int64');
|
|
||||||
output = utils.arrayToHex(structure.toArray('bn', 8));
|
|
||||||
} else {
|
|
||||||
// new Array or Object
|
|
||||||
output = new structure.constructor();
|
|
||||||
|
|
||||||
const keys = Object.keys(structure);
|
|
||||||
|
|
||||||
for (let i = 0, l = keys.length; i < l; i++) {
|
|
||||||
const key = keys[i];
|
|
||||||
output[key] = SerializedObject.jsonify_structure(structure[key], key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
output = structure;
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.serialize = function(typedef, obj) {
|
|
||||||
// Serialize object without end marker
|
|
||||||
stypes.Object.serialize(this, obj, true);
|
|
||||||
|
|
||||||
// ST: Old serialization
|
|
||||||
/*
|
|
||||||
// Ensure canonical order
|
|
||||||
typedef = SerializedObject.sort_typedef(typedef);
|
|
||||||
|
|
||||||
// Serialize fields
|
|
||||||
for (let i=0, l=typedef.length; i<l; i++) {
|
|
||||||
this.serialize_field(typedef[i], obj);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.prototype.hash = function(prefix) {
|
|
||||||
const sign_buffer = new SerializedObject();
|
|
||||||
|
|
||||||
// Add hashing prefix
|
|
||||||
if (typeof prefix !== 'undefined') {
|
|
||||||
stypes.Int32.serialize(sign_buffer, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy buffer to temporary buffer
|
|
||||||
sign_buffer.append(this.buffer);
|
|
||||||
const bytes = hashjs.sha512().update(sign_buffer.buffer).digest();
|
|
||||||
|
|
||||||
return UInt256.from_bytes(bytes.slice(0, 32));
|
|
||||||
};
|
|
||||||
|
|
||||||
// DEPRECATED
|
|
||||||
SerializedObject.prototype.signing_hash = SerializedObject.prototype.hash;
|
|
||||||
|
|
||||||
SerializedObject.prototype.serialize_field = function(spec, obj) {
|
|
||||||
const name = spec[0];
|
|
||||||
const presence = spec[1];
|
|
||||||
|
|
||||||
if (typeof obj[name] !== 'undefined') {
|
|
||||||
try {
|
|
||||||
stypes.serialize(this, name, obj[name]);
|
|
||||||
} catch (e) {
|
|
||||||
// Add field name to message and rethrow
|
|
||||||
e.message = 'Error serializing "' + name + '": ' + e.message;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} else if (presence === binformat.REQUIRED) {
|
|
||||||
throw new Error('Missing required field ' + name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.get_field_header = function(type_id, field_id) {
|
|
||||||
const buffer = [0];
|
|
||||||
|
|
||||||
if (type_id > 0xF) {
|
|
||||||
buffer.push(type_id & 0xFF);
|
|
||||||
} else {
|
|
||||||
buffer[0] += (type_id & 0xF) << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field_id > 0xF) {
|
|
||||||
buffer.push(field_id & 0xFF);
|
|
||||||
} else {
|
|
||||||
buffer[0] += field_id & 0xF;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.sort_typedef = function(typedef) {
|
|
||||||
assert(Array.isArray(typedef));
|
|
||||||
|
|
||||||
function sort_field_compare(a, b) {
|
|
||||||
// Sort by type id first, then by field id
|
|
||||||
return a[3] !== b[3] ? stypes[a[3]].id - stypes[b[3]].id : a[2] - b[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return typedef.sort(sort_field_compare);
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.lookup_type_tx = function(id) {
|
|
||||||
assert.strictEqual(typeof id, 'number');
|
|
||||||
return TRANSACTION_TYPES[id];
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedObject.lookup_type_le = function(id) {
|
|
||||||
assert(typeof id === 'number');
|
|
||||||
return LEDGER_ENTRY_TYPES[id];
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.SerializedObject = SerializedObject;
|
|
||||||
@@ -1,935 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type definitions for binary format.
|
|
||||||
*
|
|
||||||
* This file should not be included directly. Instead, find the format you're
|
|
||||||
* trying to parse or serialize in binformat.js and pass that to
|
|
||||||
* SerializedObject.parse() or SerializedObject.serialize().
|
|
||||||
*/
|
|
||||||
|
|
||||||
const _ = require('lodash');
|
|
||||||
const assert = require('assert');
|
|
||||||
const extend = require('extend');
|
|
||||||
const BN = require('bn.js');
|
|
||||||
const GlobalBigNumber = require('bignumber.js');
|
|
||||||
const sjclcodec = require('sjcl-codec');
|
|
||||||
const Amount = require('./amount').Amount;
|
|
||||||
const Currency = require('./currency').Currency;
|
|
||||||
const binformat = require('./binformat');
|
|
||||||
const utils = require('./utils');
|
|
||||||
|
|
||||||
const UInt128 = require('./uint128').UInt128;
|
|
||||||
const UInt160 = require('./uint160').UInt160;
|
|
||||||
const UInt256 = require('./uint256').UInt256;
|
|
||||||
const Base = require('./base').Base;
|
|
||||||
|
|
||||||
const BigNumber = GlobalBigNumber.another({
|
|
||||||
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
|
||||||
DECIMAL_PLACES: 40
|
|
||||||
});
|
|
||||||
|
|
||||||
function SerializedType(methods) {
|
|
||||||
extend(this, methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isNumber(val) {
|
|
||||||
return typeof val === 'number' && isFinite(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isString(val) {
|
|
||||||
return typeof val === 'string';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isHexInt64String(val) {
|
|
||||||
return isString(val) && /^[0-9A-F]{0,16}$/i.test(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeBytes(so, byteData, noLength) {
|
|
||||||
if (!noLength) {
|
|
||||||
SerializedType.serialize_varint(so, byteData.length);
|
|
||||||
}
|
|
||||||
so.append(byteData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeHex(so, hexData, noLength) {
|
|
||||||
serializeBytes(so, utils.hexToArray(hexData), noLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertHexToString(hexString) {
|
|
||||||
const bits = sjclcodec.hex.toBits(hexString);
|
|
||||||
return sjclcodec.utf8String.fromBits(bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sort_fields(keys) {
|
|
||||||
function sort_field_compare(a, b) {
|
|
||||||
const a_field_coordinates = binformat.fieldsInverseMap[a];
|
|
||||||
const a_type_bits = a_field_coordinates[0];
|
|
||||||
const a_field_bits = a_field_coordinates[1];
|
|
||||||
const b_field_coordinates = binformat.fieldsInverseMap[b];
|
|
||||||
const b_type_bits = b_field_coordinates[0];
|
|
||||||
const b_field_bits = b_field_coordinates[1];
|
|
||||||
|
|
||||||
// Sort by type id first, then by field id
|
|
||||||
return a_type_bits !== b_type_bits
|
|
||||||
? a_type_bits - b_type_bits
|
|
||||||
: a_field_bits - b_field_bits;
|
|
||||||
}
|
|
||||||
|
|
||||||
return keys.sort(sort_field_compare);
|
|
||||||
}
|
|
||||||
|
|
||||||
SerializedType.serialize_varint = function(so, val) {
|
|
||||||
let value = val;
|
|
||||||
if (value < 0) {
|
|
||||||
throw new Error('Variable integers are unsigned.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value <= 192) {
|
|
||||||
so.append([value]);
|
|
||||||
} else if (value <= 12480) {
|
|
||||||
value -= 193;
|
|
||||||
so.append([193 + (value >>> 8), value & 0xff]);
|
|
||||||
} else if (value <= 918744) {
|
|
||||||
value -= 12481;
|
|
||||||
so.append([241 + (value >>> 16), value >>> 8 & 0xff, value & 0xff]);
|
|
||||||
} else {
|
|
||||||
throw new Error('Variable integer overflow.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedType.prototype.parse_varint = function(so) {
|
|
||||||
const b1 = so.read(1)[0];
|
|
||||||
let b2;
|
|
||||||
let b3;
|
|
||||||
let result;
|
|
||||||
|
|
||||||
if (b1 > 254) {
|
|
||||||
throw new Error('Invalid varint length indicator');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b1 <= 192) {
|
|
||||||
result = b1;
|
|
||||||
} else if (b1 <= 240) {
|
|
||||||
b2 = so.read(1)[0];
|
|
||||||
result = 193 + (b1 - 193) * 256 + b2;
|
|
||||||
} else if (b1 <= 254) {
|
|
||||||
b2 = so.read(1)[0];
|
|
||||||
b3 = so.read(1)[0];
|
|
||||||
result = 12481 + (b1 - 241) * 65536 + b2 * 256 + b3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
// In the following, we assume that the inputs are in the proper range. Is this
|
|
||||||
// correct?
|
|
||||||
// Helper functions for 1-, 2-, and 4-byte integers.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an integer value into an array of bytes.
|
|
||||||
*
|
|
||||||
* The result is appended to the serialized object ('so').
|
|
||||||
*
|
|
||||||
* @param {Number} val value
|
|
||||||
* @param {Number} bytes byte size
|
|
||||||
* @return {Array} byte array
|
|
||||||
*/
|
|
||||||
function convertIntegerToByteArray(val, bytes) {
|
|
||||||
if (!isNumber(val)) {
|
|
||||||
throw new Error('Value is not a number', bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val < 0 || val >= Math.pow(256, bytes)) {
|
|
||||||
throw new Error('Value out of bounds ');
|
|
||||||
}
|
|
||||||
|
|
||||||
const newBytes = [ ];
|
|
||||||
|
|
||||||
for (let i = 0; i < bytes; i++) {
|
|
||||||
newBytes.unshift(val >>> (i * 8) & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert a certain number of bytes from the serialized object ('so') into an
|
|
||||||
// integer.
|
|
||||||
function readAndSum(so, bytes) {
|
|
||||||
let sum = 0;
|
|
||||||
|
|
||||||
if (bytes > 4) {
|
|
||||||
throw new Error('This function only supports up to four bytes.');
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < bytes; i++) {
|
|
||||||
const byte = so.read(1)[0];
|
|
||||||
sum += (byte << (8 * (bytes - i - 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to unsigned integer
|
|
||||||
return sum >>> 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const STInt8 = exports.Int8 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
so.append(convertIntegerToByteArray(val, 1));
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
return readAndSum(so, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STInt8.id = 16;
|
|
||||||
|
|
||||||
function serialize(so, field_name, value) {
|
|
||||||
// so: a byte-stream to serialize into.
|
|
||||||
// field_name: a string for the field name ('LedgerEntryType' etc.)
|
|
||||||
// value: the value of that field.
|
|
||||||
const field_coordinates = binformat.fieldsInverseMap[field_name];
|
|
||||||
const type_bits = field_coordinates[0];
|
|
||||||
const field_bits = field_coordinates[1];
|
|
||||||
const tag_byte = (type_bits < 16
|
|
||||||
? type_bits << 4
|
|
||||||
: 0) | (field_bits < 16
|
|
||||||
? field_bits
|
|
||||||
: 0);
|
|
||||||
let val = value;
|
|
||||||
|
|
||||||
if (field_name === 'LedgerEntryType' && typeof val === 'string') {
|
|
||||||
val = binformat.ledger[val][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field_name === 'TransactionResult' && typeof val === 'string') {
|
|
||||||
val = binformat.ter[val];
|
|
||||||
}
|
|
||||||
|
|
||||||
STInt8.serialize(so, tag_byte);
|
|
||||||
|
|
||||||
if (type_bits >= 16) {
|
|
||||||
STInt8.serialize(so, type_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field_bits >= 16) {
|
|
||||||
STInt8.serialize(so, field_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the serializer class (ST...)
|
|
||||||
let serialized_object_type;
|
|
||||||
|
|
||||||
if (field_name === 'Memo' && typeof val === 'object') {
|
|
||||||
// for Memo we override the default behavior with our STMemo serializer
|
|
||||||
serialized_object_type = exports.STMemo;
|
|
||||||
} else {
|
|
||||||
// for a field based on the type bits.
|
|
||||||
serialized_object_type = exports[binformat.types[type_bits]];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
serialized_object_type.serialize(so, val);
|
|
||||||
} catch (e) {
|
|
||||||
e.message += ' (' + field_name + ')';
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.serialize = exports.serialize_whatever = serialize;
|
|
||||||
|
|
||||||
// Take the serialized object, figure out what type/field it is, and return the
|
|
||||||
// parsing of that.
|
|
||||||
|
|
||||||
function parse(so) {
|
|
||||||
const tag_byte = so.read(1)[0];
|
|
||||||
let type_bits = tag_byte >> 4;
|
|
||||||
|
|
||||||
if (type_bits === 0) {
|
|
||||||
type_bits = so.read(1)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const field_bits = tag_byte & 0x0f;
|
|
||||||
const field_name = (field_bits === 0)
|
|
||||||
? binformat.fields[type_bits][so.read(1)[0]]
|
|
||||||
: binformat.fields[type_bits][field_bits];
|
|
||||||
|
|
||||||
assert(field_name, 'Unknown field - header byte is 0x'
|
|
||||||
+ tag_byte.toString(16));
|
|
||||||
|
|
||||||
// Get the parser class (ST...) for a field based on the type bits.
|
|
||||||
const type = (field_name === 'Memo')
|
|
||||||
? exports.STMemo
|
|
||||||
: exports[binformat.types[type_bits]];
|
|
||||||
|
|
||||||
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
|
||||||
|
|
||||||
return [field_name, type.parse(so)]; // key, value
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.parse = exports.parse_whatever = parse;
|
|
||||||
|
|
||||||
const STInt16 = exports.Int16 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
so.append(convertIntegerToByteArray(val, 2));
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
return readAndSum(so, 2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STInt16.id = 1;
|
|
||||||
|
|
||||||
const STInt32 = exports.Int32 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
so.append(convertIntegerToByteArray(val, 4));
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
return readAndSum(so, 4);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STInt32.id = 2;
|
|
||||||
|
|
||||||
const STInt64 = exports.Int64 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
let bigNumObject;
|
|
||||||
let value = val;
|
|
||||||
|
|
||||||
if (isNumber(value)) {
|
|
||||||
value = Math.floor(value);
|
|
||||||
if (value < 0) {
|
|
||||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
|
||||||
}
|
|
||||||
bigNumObject = new BN(value, 10);
|
|
||||||
} else if (isString(value)) {
|
|
||||||
if (!isHexInt64String(value)) {
|
|
||||||
throw new Error('Not a valid hex Int64.');
|
|
||||||
}
|
|
||||||
bigNumObject = new BN(value, 16);
|
|
||||||
} else if (value instanceof BN) {
|
|
||||||
if (value.cmpn(0) < 0) {
|
|
||||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
|
||||||
}
|
|
||||||
bigNumObject = value;
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid type for Int64: ' + (typeof value) + ' value');
|
|
||||||
}
|
|
||||||
// `'be'` means big endian, and the following arg is the byte length, which
|
|
||||||
// it will pad with 0s to if not enough bytes, or throw if over
|
|
||||||
serializeBytes(so, bigNumObject.toArray('be', 8), /* noLength= */true);
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const bytes = so.read(8);
|
|
||||||
return new BN(bytes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STInt64.id = 3;
|
|
||||||
|
|
||||||
const STHash128 = exports.Hash128 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
const hash = UInt128.from_json(val);
|
|
||||||
if (!hash.is_valid()) {
|
|
||||||
throw new Error('Invalid Hash128');
|
|
||||||
}
|
|
||||||
serializeBytes(so, hash.to_bytes(), true); // noLength = true
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
return UInt128.from_bytes(so.read(16));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STHash128.id = 4;
|
|
||||||
|
|
||||||
const STHash256 = exports.Hash256 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
const hash = UInt256.from_json(val);
|
|
||||||
if (!hash.is_valid()) {
|
|
||||||
throw new Error('Invalid Hash256');
|
|
||||||
}
|
|
||||||
serializeBytes(so, hash.to_bytes(), true); // noLength = true
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
return UInt256.from_bytes(so.read(32));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STHash256.id = 5;
|
|
||||||
|
|
||||||
const STHash160 = exports.Hash160 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
const hash = UInt160.from_json(val);
|
|
||||||
if (!hash.is_valid()) {
|
|
||||||
throw new Error('Invalid Hash160');
|
|
||||||
}
|
|
||||||
serializeBytes(so, hash.to_bytes(), true); // noLength = true
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
return UInt160.from_bytes(so.read(20));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STHash160.id = 17;
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
const STCurrency = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
const currencyData = val.to_bytes();
|
|
||||||
|
|
||||||
if (!currencyData) {
|
|
||||||
throw new Error(
|
|
||||||
'Tried to serialize invalid/unimplemented currency type.');
|
|
||||||
}
|
|
||||||
|
|
||||||
so.append(currencyData);
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const bytes = so.read(20);
|
|
||||||
const currency = Currency.from_bytes(bytes);
|
|
||||||
// XXX Disabled check. Theoretically, the Currency class should support any
|
|
||||||
// UInt160 value and consider it valid. But it doesn't, so for the
|
|
||||||
// deserialization to be usable, we need to allow invalid results for
|
|
||||||
// now.
|
|
||||||
// if (!currency.is_valid()) {
|
|
||||||
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
|
|
||||||
// }
|
|
||||||
return currency;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quality is encoded into 64 bits:
|
|
||||||
* (8 bits offset) (56 bits mantissa)
|
|
||||||
*
|
|
||||||
* Quality differs from Amount because it does not need the first two bits
|
|
||||||
* to represent non-native and non-negative
|
|
||||||
*/
|
|
||||||
exports.Quality = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
let value;
|
|
||||||
// if in format: amount/currency/issuer
|
|
||||||
if (_.includes(val, '/')) {
|
|
||||||
const amount = Amount.from_json(val);
|
|
||||||
|
|
||||||
if (!amount.is_valid()) {
|
|
||||||
throw new Error('Not a valid Amount object.');
|
|
||||||
}
|
|
||||||
value = new BigNumber(amount.to_text());
|
|
||||||
} else {
|
|
||||||
value = new BigNumber(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
let hi = 0;
|
|
||||||
let lo = 0;
|
|
||||||
|
|
||||||
const offset = value.e - 15;
|
|
||||||
if (val !== 0) {
|
|
||||||
// First eight bits: offset/exponent
|
|
||||||
hi |= ((100 + offset) & 0xff) << 24;
|
|
||||||
|
|
||||||
// Remaining 56 bits: mantissa
|
|
||||||
const mantissaDecimal = utils.getMantissaDecimalString(value.abs());
|
|
||||||
const mantissaHex = (new BigNumber(mantissaDecimal)).toString(16);
|
|
||||||
assert(mantissaHex.length <= 16,
|
|
||||||
'Mantissa hex representation ' + mantissaHex +
|
|
||||||
' exceeds the maximum length of 16');
|
|
||||||
hi |= parseInt(mantissaHex.slice(0, -8), 16) & 0xffffff;
|
|
||||||
lo = parseInt(mantissaHex.slice(-8), 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueBytes = sjclcodec.bytes.fromBits([hi, lo]);
|
|
||||||
|
|
||||||
so.append(valueBytes);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Amount is encoded into 64 bits:
|
|
||||||
* (1 bit non-native) (1 bit non-negative) (8 bits offset) (54 bits mantissa)
|
|
||||||
*/
|
|
||||||
const STAmount = exports.Amount = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
const amount = Amount.from_json(val);
|
|
||||||
|
|
||||||
if (!amount.is_valid()) {
|
|
||||||
throw new Error('Not a valid Amount object.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = new BigNumber(amount.to_text());
|
|
||||||
const offset = value.e - 15;
|
|
||||||
|
|
||||||
// Amount (64-bit integer)
|
|
||||||
let valueBytes = utils.arraySet(8, 0);
|
|
||||||
|
|
||||||
if (amount.is_native()) {
|
|
||||||
let valueHex = value.abs().toString(16);
|
|
||||||
|
|
||||||
if (Amount.strict_mode && value.abs().greaterThan(Amount.bi_xns_max)) {
|
|
||||||
throw new Error('Value out of bounds');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce correct length (64 bits)
|
|
||||||
if (Amount.strict_mode && valueHex.length > 16) {
|
|
||||||
throw new Error('Value out of bounds');
|
|
||||||
}
|
|
||||||
|
|
||||||
while (valueHex.length < 16) {
|
|
||||||
valueHex = '0' + valueHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
valueBytes = sjclcodec.bytes.fromBits(sjclcodec.hex.toBits(valueHex));
|
|
||||||
// Clear most significant two bits - these bits should already be 0 if
|
|
||||||
// Amount enforces the range correctly, but we'll clear them anyway just
|
|
||||||
// so this code can make certain guarantees about the encoded value.
|
|
||||||
valueBytes[0] &= 0x3f;
|
|
||||||
|
|
||||||
if (!amount.is_negative()) {
|
|
||||||
valueBytes[0] |= 0x40;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let hi = 0;
|
|
||||||
let lo = 0;
|
|
||||||
|
|
||||||
// First bit: non-native
|
|
||||||
hi |= 1 << 31;
|
|
||||||
|
|
||||||
if (!amount.is_zero()) {
|
|
||||||
// Second bit: non-negative?
|
|
||||||
if (!amount.is_negative()) {
|
|
||||||
hi |= 1 << 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next eight bits: offset/exponent
|
|
||||||
hi |= ((97 + offset) & 0xff) << 22;
|
|
||||||
|
|
||||||
// Remaining 54 bits: mantissa
|
|
||||||
const mantissaDecimal = utils.getMantissaDecimalString(value.abs());
|
|
||||||
const mantissaHex = (new BigNumber(mantissaDecimal)).toString(16);
|
|
||||||
assert(mantissaHex.length <= 16,
|
|
||||||
'Mantissa hex representation ' + mantissaHex +
|
|
||||||
' exceeds the maximum length of 16');
|
|
||||||
hi |= parseInt(mantissaHex.slice(0, -8), 16) & 0x3fffff;
|
|
||||||
lo = parseInt(mantissaHex.slice(-8), 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
valueBytes = sjclcodec.bytes.fromBits([hi, lo]);
|
|
||||||
}
|
|
||||||
|
|
||||||
so.append(valueBytes);
|
|
||||||
|
|
||||||
if (!amount.is_native()) {
|
|
||||||
// Currency (160-bit hash)
|
|
||||||
const currency = amount.currency();
|
|
||||||
STCurrency.serialize(so, currency, true);
|
|
||||||
|
|
||||||
// Issuer (160-bit hash)
|
|
||||||
so.append(UInt160.from_json(amount.issuer()).to_bytes());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const value_bytes = so.read(8);
|
|
||||||
let is_zero = !(value_bytes[0] & 0x7f);
|
|
||||||
|
|
||||||
for (let i = 1; i < 8; i++) {
|
|
||||||
is_zero = is_zero && !value_bytes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
const is_negative = !is_zero && !(value_bytes[0] & 0x40);
|
|
||||||
|
|
||||||
if (value_bytes[0] & 0x80) {
|
|
||||||
// non-native
|
|
||||||
const currency = STCurrency.parse(so);
|
|
||||||
const issuer_bytes = so.read(20);
|
|
||||||
const issuer = UInt160.from_bytes(issuer_bytes);
|
|
||||||
issuer.set_version(Base.VER_ACCOUNT_ID);
|
|
||||||
const offset =
|
|
||||||
((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
|
|
||||||
const mantissa_bytes = value_bytes.slice(1);
|
|
||||||
mantissa_bytes[0] &= 0x3f;
|
|
||||||
const mantissa = new BigNumber(utils.arrayToHex(mantissa_bytes), 16);
|
|
||||||
const sign = is_negative ? '-' : '';
|
|
||||||
const valueString = sign + mantissa.toString() + 'e' + offset.toString();
|
|
||||||
|
|
||||||
return Amount.from_json({
|
|
||||||
currency: currency,
|
|
||||||
issuer: issuer.to_json(),
|
|
||||||
value: valueString
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// native
|
|
||||||
const integer_bytes = value_bytes.slice();
|
|
||||||
integer_bytes[0] &= 0x3f;
|
|
||||||
const integer_hex = utils.arrayToHex(integer_bytes);
|
|
||||||
const value = new BigNumber(integer_hex, 16);
|
|
||||||
return Amount.from_json((is_negative ? '-' : '') + value.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STAmount.id = 6;
|
|
||||||
|
|
||||||
const STVL = exports.VariableLength = exports.VL = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
if (typeof val === 'string') {
|
|
||||||
serializeHex(so, val);
|
|
||||||
} else {
|
|
||||||
throw new Error('Unknown datatype.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const len = this.parse_varint(so);
|
|
||||||
return utils.arrayToHex(so.read(len));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STVL.id = 7;
|
|
||||||
|
|
||||||
const STAccount = exports.Account = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
const account = UInt160.from_json(val);
|
|
||||||
if (!account.is_valid()) {
|
|
||||||
throw new Error('Invalid account!');
|
|
||||||
}
|
|
||||||
serializeBytes(so, account.to_bytes());
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const len = this.parse_varint(so);
|
|
||||||
|
|
||||||
if (len !== 20) {
|
|
||||||
throw new Error('Non-standard-length account ID');
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = UInt160.from_bytes(so.read(len));
|
|
||||||
result.set_version(Base.VER_ACCOUNT_ID);
|
|
||||||
|
|
||||||
if (false && !result.is_valid()) {
|
|
||||||
throw new Error('Invalid Account');
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STAccount.id = 8;
|
|
||||||
|
|
||||||
const STPathSet = exports.PathSet = new SerializedType({
|
|
||||||
typeBoundary: 0xff,
|
|
||||||
typeEnd: 0x00,
|
|
||||||
typeAccount: 0x01,
|
|
||||||
typeCurrency: 0x10,
|
|
||||||
typeIssuer: 0x20,
|
|
||||||
serialize: function(so, val) {
|
|
||||||
for (let i = 0, l = val.length; i < l; i++) {
|
|
||||||
// Boundary
|
|
||||||
if (i) {
|
|
||||||
STInt8.serialize(so, this.typeBoundary);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = 0, l2 = val[i].length; j < l2; j++) {
|
|
||||||
const entry = val[i][j];
|
|
||||||
// if (entry.hasOwnProperty('_value')) {entry = entry._value;}
|
|
||||||
let type = 0;
|
|
||||||
|
|
||||||
if (entry.account) {
|
|
||||||
type |= this.typeAccount;
|
|
||||||
}
|
|
||||||
if (entry.currency) {
|
|
||||||
type |= this.typeCurrency;
|
|
||||||
}
|
|
||||||
if (entry.issuer) {
|
|
||||||
type |= this.typeIssuer;
|
|
||||||
}
|
|
||||||
|
|
||||||
STInt8.serialize(so, type);
|
|
||||||
|
|
||||||
if (entry.account) {
|
|
||||||
STHash160.serialize(so, entry.account);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.currency) {
|
|
||||||
const currency = Currency.from_json(entry.currency, entry.non_native);
|
|
||||||
STCurrency.serialize(so, currency);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.issuer) {
|
|
||||||
STHash160.serialize(so, entry.issuer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
STInt8.serialize(so, this.typeEnd);
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
// should return a list of lists:
|
|
||||||
/*
|
|
||||||
[
|
|
||||||
[entry, entry],
|
|
||||||
[entry, entry, entry],
|
|
||||||
[entry],
|
|
||||||
[]
|
|
||||||
]
|
|
||||||
|
|
||||||
each entry has one or more of the following attributes:
|
|
||||||
amount, currency, issuer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const path_list = [];
|
|
||||||
let current_path = [];
|
|
||||||
let tag_byte;
|
|
||||||
|
|
||||||
/* eslint-disable no-cond-assign */
|
|
||||||
|
|
||||||
while ((tag_byte = so.read(1)[0]) !== this.typeEnd) {
|
|
||||||
// TODO: try/catch this loop, and catch when we run out of data without
|
|
||||||
// reaching the end of the data structure.
|
|
||||||
// Now determine: is this an end, boundary, or entry-begin-tag?
|
|
||||||
// console.log('Tag byte:', tag_byte);
|
|
||||||
if (tag_byte === this.typeBoundary) {
|
|
||||||
if (current_path) { // close the current path, if there is one,
|
|
||||||
path_list.push(current_path);
|
|
||||||
}
|
|
||||||
current_path = [ ]; // and start a new one.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's an entry-begin tag.
|
|
||||||
const entry = {};
|
|
||||||
let type = 0;
|
|
||||||
|
|
||||||
if (tag_byte & this.typeAccount) {
|
|
||||||
entry.account = STHash160.parse(so);
|
|
||||||
entry.account.set_version(Base.VER_ACCOUNT_ID);
|
|
||||||
type = type | this.typeAccount;
|
|
||||||
}
|
|
||||||
if (tag_byte & this.typeCurrency) {
|
|
||||||
entry.currency = STCurrency.parse(so);
|
|
||||||
if (entry.currency.to_json() === 'XRP' && !entry.currency.is_native()) {
|
|
||||||
entry.non_native = true;
|
|
||||||
}
|
|
||||||
type = type | this.typeCurrency;
|
|
||||||
}
|
|
||||||
if (tag_byte & this.typeIssuer) {
|
|
||||||
entry.issuer = STHash160.parse(so);
|
|
||||||
// Enable and set correct type of base-58 encoding
|
|
||||||
entry.issuer.set_version(Base.VER_ACCOUNT_ID);
|
|
||||||
type = type | this.typeIssuer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.account || entry.currency || entry.issuer) {
|
|
||||||
entry.type = type;
|
|
||||||
entry.type_hex = ('000000000000000' + type.toString(16)).slice(-16);
|
|
||||||
current_path.push(entry);
|
|
||||||
} else {
|
|
||||||
// It must have at least something in it.
|
|
||||||
throw new Error('Invalid path entry');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_path) {
|
|
||||||
// close the current path, if there is one,
|
|
||||||
path_list.push(current_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return path_list;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STPathSet.id = 18;
|
|
||||||
|
|
||||||
const STVector256 = exports.Vector256 = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
// Assume val is an array of STHash256 objects.
|
|
||||||
SerializedType.serialize_varint(so, val.length * 32);
|
|
||||||
for (let i = 0, l = val.length; i < l; i++) {
|
|
||||||
STHash256.serialize(so, val[i]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const length = this.parse_varint(so);
|
|
||||||
const output = [];
|
|
||||||
// length is number of bytes not number of Hash256
|
|
||||||
for (let i = 0; i < length / 32; i++) {
|
|
||||||
output.push(STHash256.parse(so));
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STVector256.id = 19;
|
|
||||||
|
|
||||||
// Internal
|
|
||||||
exports.STMemo = new SerializedType({
|
|
||||||
serialize: function(so, val, no_marker) {
|
|
||||||
let keys = [];
|
|
||||||
|
|
||||||
Object.keys(val).forEach(function(key) {
|
|
||||||
// Ignore lowercase field names - they're non-serializable fields by
|
|
||||||
// convention.
|
|
||||||
if (key[0] === key[0].toLowerCase()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
|
||||||
throw new Error('JSON contains unknown field: "' + key + '"');
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.push(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort fields
|
|
||||||
keys = sort_fields(keys);
|
|
||||||
|
|
||||||
keys.forEach(function(key) {
|
|
||||||
serialize(so, key, val[key]);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!no_marker) {
|
|
||||||
// Object ending marker
|
|
||||||
STInt8.serialize(so, 0xe1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
parse: function(so) {
|
|
||||||
const output = {};
|
|
||||||
|
|
||||||
while (so.peek(1)[0] !== 0xe1) {
|
|
||||||
const keyval = parse(so);
|
|
||||||
output[keyval[0]] = keyval[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output.MemoType !== undefined) {
|
|
||||||
try {
|
|
||||||
const parsedType = convertHexToString(output.MemoType);
|
|
||||||
|
|
||||||
if (parsedType !== 'unformatted_memo') {
|
|
||||||
output.parsed_memo_type = parsedType;
|
|
||||||
}
|
|
||||||
/* eslint-disable no-empty */
|
|
||||||
} catch (e) {
|
|
||||||
// empty
|
|
||||||
// we don't know what's in the binary, apparently it's not a UTF-8
|
|
||||||
// string
|
|
||||||
// this is fine, we won't add the parsed_memo_type field
|
|
||||||
}
|
|
||||||
/* eslint-enable no-empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output.MemoFormat !== undefined) {
|
|
||||||
try {
|
|
||||||
output.parsed_memo_format = convertHexToString(output.MemoFormat);
|
|
||||||
/* eslint-disable no-empty */
|
|
||||||
} catch (e) {
|
|
||||||
// empty
|
|
||||||
// we don't know what's in the binary, apparently it's not a UTF-8
|
|
||||||
// string
|
|
||||||
// this is fine, we won't add the parsed_memo_format field
|
|
||||||
}
|
|
||||||
/* eslint-enable no-empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output.MemoData !== undefined) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (output.parsed_memo_format === 'json') {
|
|
||||||
// see if we can parse JSON
|
|
||||||
output.parsed_memo_data =
|
|
||||||
JSON.parse(convertHexToString(output.MemoData));
|
|
||||||
|
|
||||||
} else if (output.parsed_memo_format === 'text') {
|
|
||||||
// otherwise see if we can parse text
|
|
||||||
output.parsed_memo_data = convertHexToString(output.MemoData);
|
|
||||||
}
|
|
||||||
/* eslint-disable no-empty */
|
|
||||||
} catch (e) {
|
|
||||||
// empty
|
|
||||||
// we'll fail in case the content does not match what the MemoFormat
|
|
||||||
// described
|
|
||||||
// this is fine, we won't add the parsed_memo_data, the user has to
|
|
||||||
// parse themselves
|
|
||||||
}
|
|
||||||
/* eslint-enable no-empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
so.read(1);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
const STObject = exports.Object = new SerializedType({
|
|
||||||
serialize: function(so, val, no_marker) {
|
|
||||||
let keys = [];
|
|
||||||
|
|
||||||
Object.keys(val).forEach(function(key) {
|
|
||||||
// Ignore lowercase field names - they're non-serializable fields by
|
|
||||||
// convention.
|
|
||||||
if (key[0] === key[0].toLowerCase()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof binformat.fieldsInverseMap[key] === 'undefined') {
|
|
||||||
throw new Error('JSON contains unknown field: "' + key + '"');
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.push(key);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort fields
|
|
||||||
keys = sort_fields(keys);
|
|
||||||
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
|
||||||
serialize(so, keys[i], val[keys[i]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!no_marker) {
|
|
||||||
// Object ending marker
|
|
||||||
STInt8.serialize(so, 0xe1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
parse: function(so) {
|
|
||||||
const output = {};
|
|
||||||
while (so.peek(1)[0] !== 0xe1) {
|
|
||||||
const keyval = parse(so);
|
|
||||||
output[keyval[0]] = keyval[1];
|
|
||||||
}
|
|
||||||
so.read(1);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STObject.id = 14;
|
|
||||||
|
|
||||||
const STArray = exports.Array = new SerializedType({
|
|
||||||
serialize: function(so, val) {
|
|
||||||
for (let i = 0, l = val.length; i < l; i++) {
|
|
||||||
const keys = Object.keys(val[i]);
|
|
||||||
|
|
||||||
if (keys.length !== 1) {
|
|
||||||
throw new Error(
|
|
||||||
'Cannot serialize an array containing non-single-key objects');
|
|
||||||
}
|
|
||||||
|
|
||||||
const field_name = keys[0];
|
|
||||||
const value = val[i][field_name];
|
|
||||||
serialize(so, field_name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array ending marker
|
|
||||||
STInt8.serialize(so, 0xf1);
|
|
||||||
},
|
|
||||||
|
|
||||||
parse: function(so) {
|
|
||||||
const output = [ ];
|
|
||||||
|
|
||||||
while (so.peek(1)[0] !== 0xf1) {
|
|
||||||
const keyval = parse(so);
|
|
||||||
const obj = { };
|
|
||||||
obj[keyval[0]] = keyval[1];
|
|
||||||
output.push(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
so.read(1);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
STArray.id = 15;
|
|
||||||
269
src/core/uint.js
269
src/core/uint.js
@@ -1,269 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/* eslint new-cap: 1 */
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const lodash = require('lodash');
|
|
||||||
const sjclcodec = require('sjcl-codec');
|
|
||||||
const utils = require('./utils');
|
|
||||||
const BN = require('bn.js');
|
|
||||||
|
|
||||||
//
|
|
||||||
// Abstract UInt class
|
|
||||||
//
|
|
||||||
// Base class for UInt classes
|
|
||||||
//
|
|
||||||
|
|
||||||
function UInt() {
|
|
||||||
// Internal form: NaN or BN
|
|
||||||
this._value = NaN;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt.json_rewrite = function(j, opts) {
|
|
||||||
return this.from_json(j).to_json(opts);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a new UInt from j.
|
|
||||||
UInt.from_generic = function(j) {
|
|
||||||
if (j instanceof this) {
|
|
||||||
return j.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new this()).parse_generic(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a new UInt from j.
|
|
||||||
UInt.from_hex = function(j) {
|
|
||||||
if (j instanceof this) {
|
|
||||||
return j.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new this()).parse_hex(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a new UInt from j.
|
|
||||||
UInt.from_json = function(j) {
|
|
||||||
if (j instanceof this) {
|
|
||||||
return j.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new this()).parse_json(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a new UInt from j.
|
|
||||||
UInt.from_bits = function(j) {
|
|
||||||
if (j instanceof this) {
|
|
||||||
return j.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new this()).parse_bits(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a new UInt from j.
|
|
||||||
UInt.from_bytes = function(j) {
|
|
||||||
if (j instanceof this) {
|
|
||||||
return j.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new this()).parse_bytes(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return a new UInt from j.
|
|
||||||
UInt.from_number = function(j) {
|
|
||||||
if (j instanceof this) {
|
|
||||||
return j.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (new this()).parse_number(j);
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.is_valid = function(j) {
|
|
||||||
return this.from_json(j).is_valid();
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.clone = function() {
|
|
||||||
return this.copyTo(new this.constructor());
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns copy.
|
|
||||||
UInt.prototype.copyTo = function(d) {
|
|
||||||
d._value = this._value;
|
|
||||||
|
|
||||||
if (this._version_byte !== undefined) {
|
|
||||||
d._version_byte = this._version_byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof d._update === 'function') {
|
|
||||||
d._update();
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.equals = function(o) {
|
|
||||||
return this.is_valid() &&
|
|
||||||
o.is_valid() &&
|
|
||||||
// This throws but the expression will short circuit
|
|
||||||
this.cmp(o) === 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.cmp = function(o) {
|
|
||||||
assert(this.is_valid() && o.is_valid());
|
|
||||||
return this._value.cmp(o._value);
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.greater_than = function(o) {
|
|
||||||
return this.cmp(o) > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.less_than = function(o) {
|
|
||||||
return this.cmp(o) < 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.is_valid = function() {
|
|
||||||
return this._value instanceof BN;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.is_zero = function() {
|
|
||||||
// cmpn means cmp with N)umber
|
|
||||||
return this.is_valid() && this._value.cmpn(0) === 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update any derivative values.
|
|
||||||
*
|
|
||||||
* This allows subclasses to maintain caches of any data that they derive from
|
|
||||||
* the main _value. For example, the Currency class keeps the currency type, the
|
|
||||||
* currency code and other information about the currency cached.
|
|
||||||
*
|
|
||||||
* The reason for keeping this mechanism in this class is so every subclass can
|
|
||||||
* call it whenever it modifies the internal state.
|
|
||||||
*
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
UInt.prototype._update = function() {
|
|
||||||
// Nothing to do by default. Subclasses will override this.
|
|
||||||
};
|
|
||||||
|
|
||||||
// value = NaN on error.
|
|
||||||
UInt.prototype.parse_generic = function(j) {
|
|
||||||
const subclass = this.constructor;
|
|
||||||
|
|
||||||
assert(typeof subclass.width === 'number', 'UInt missing width');
|
|
||||||
|
|
||||||
this._value = NaN;
|
|
||||||
|
|
||||||
switch (j) {
|
|
||||||
case undefined:
|
|
||||||
case '0':
|
|
||||||
case subclass.STR_ZERO:
|
|
||||||
case subclass.ACCOUNT_ZERO:
|
|
||||||
case subclass.HEX_ZERO:
|
|
||||||
this._value = new BN(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '1':
|
|
||||||
case subclass.STR_ONE:
|
|
||||||
case subclass.ACCOUNT_ONE:
|
|
||||||
case subclass.HEX_ONE:
|
|
||||||
this._value = new BN(1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (lodash.isString(j)) {
|
|
||||||
switch (j.length) {
|
|
||||||
case subclass.width:
|
|
||||||
const hex = utils.arrayToHex(utils.stringToArray(j));
|
|
||||||
this._value = new BN(hex, 16);
|
|
||||||
break;
|
|
||||||
case subclass.width * 2:
|
|
||||||
// Assume hex, check char set
|
|
||||||
this.parse_hex(j);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (lodash.isNumber(j)) {
|
|
||||||
this.parse_number(j);
|
|
||||||
} else if (lodash.isArray(j)) {
|
|
||||||
// Assume bytes array
|
|
||||||
this.parse_bytes(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._update();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.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;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.parse_bits = function(j) {
|
|
||||||
return this.parse_bytes(sjclcodec.bytes.fromBits(j));
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.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;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.parse_json = UInt.prototype.parse_hex;
|
|
||||||
|
|
||||||
UInt.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;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert from internal form.
|
|
||||||
UInt.prototype.to_bytes = function() {
|
|
||||||
if (!this.is_valid()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._value.toArray('be', this.constructor.width);
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.to_hex = function() {
|
|
||||||
if (!this.is_valid()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return utils.arrayToHex(this.to_bytes());
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt.prototype.to_json = UInt.prototype.to_hex;
|
|
||||||
|
|
||||||
// Convert from internal form.
|
|
||||||
UInt.prototype.to_bits = function() {
|
|
||||||
if (!this.is_valid()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sjclcodec.bytes.toBits(this.to_bytes());
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.UInt = UInt;
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const utils = require('./utils');
|
|
||||||
const extend = require('extend');
|
|
||||||
const UInt = require('./uint').UInt;
|
|
||||||
|
|
||||||
//
|
|
||||||
// UInt128 support
|
|
||||||
//
|
|
||||||
|
|
||||||
const UInt128 = extend(function() {
|
|
||||||
this._value = NaN;
|
|
||||||
}, UInt);
|
|
||||||
|
|
||||||
UInt128.width = 16;
|
|
||||||
UInt128.prototype = Object.create(extend({}, UInt.prototype));
|
|
||||||
UInt128.prototype.constructor = UInt128;
|
|
||||||
|
|
||||||
const HEX_ZERO = UInt128.HEX_ZERO = '00000000000000000000000000000000';
|
|
||||||
const HEX_ONE = UInt128.HEX_ONE = '00000000000000000000000000000000';
|
|
||||||
|
|
||||||
UInt128.STR_ZERO = utils.hexToString(HEX_ZERO);
|
|
||||||
UInt128.STR_ONE = utils.hexToString(HEX_ONE);
|
|
||||||
|
|
||||||
exports.UInt128 = UInt128;
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const utils = require('./utils');
|
|
||||||
const extend = require('extend');
|
|
||||||
|
|
||||||
const UInt = require('./uint').UInt;
|
|
||||||
const Base = require('./base').Base;
|
|
||||||
|
|
||||||
//
|
|
||||||
// UInt160 support
|
|
||||||
//
|
|
||||||
|
|
||||||
const UInt160 = extend(function() {
|
|
||||||
this._value = NaN;
|
|
||||||
this._version_byte = undefined;
|
|
||||||
this._update();
|
|
||||||
}, UInt);
|
|
||||||
|
|
||||||
UInt160.width = 20;
|
|
||||||
UInt160.prototype = Object.create(extend({}, UInt.prototype));
|
|
||||||
UInt160.prototype.constructor = UInt160;
|
|
||||||
|
|
||||||
const HEX_ZERO = UInt160.HEX_ZERO = '0000000000000000000000000000000000000000';
|
|
||||||
const HEX_ONE = UInt160.HEX_ONE = '0000000000000000000000000000000000000001';
|
|
||||||
|
|
||||||
UInt160.ACCOUNT_ZERO = 'rrrrrrrrrrrrrrrrrrrrrhoLvTp';
|
|
||||||
UInt160.ACCOUNT_ONE = 'rrrrrrrrrrrrrrrrrrrrBZbvji';
|
|
||||||
UInt160.STR_ZERO = utils.hexToString(HEX_ZERO);
|
|
||||||
UInt160.STR_ONE = utils.hexToString(HEX_ONE);
|
|
||||||
|
|
||||||
UInt160.prototype.set_version = function(j) {
|
|
||||||
this._version_byte = j;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt160.prototype.get_version = function() {
|
|
||||||
return this._version_byte;
|
|
||||||
};
|
|
||||||
|
|
||||||
// value = NaN on error.
|
|
||||||
UInt160.prototype.parse_json = function(j) {
|
|
||||||
if (typeof j === 'number' && !isNaN(j)) {
|
|
||||||
// Allow raw numbers - DEPRECATED
|
|
||||||
// This is used mostly by the test suite and is supported
|
|
||||||
// as a legacy feature only. DO NOT RELY ON THIS BEHAVIOR.
|
|
||||||
this.parse_number(j);
|
|
||||||
this._version_byte = Base.VER_ACCOUNT_ID;
|
|
||||||
} else if (typeof j !== 'string') {
|
|
||||||
this._value = NaN;
|
|
||||||
} else if (j[0] === 'r') {
|
|
||||||
this._value = Base.decode_check(Base.VER_ACCOUNT_ID, j);
|
|
||||||
this._version_byte = Base.VER_ACCOUNT_ID;
|
|
||||||
} else {
|
|
||||||
this.parse_hex(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._update();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
UInt160.prototype.parse_generic = function(j) {
|
|
||||||
UInt.prototype.parse_generic.call(this, j);
|
|
||||||
|
|
||||||
if (isNaN(this._value)) {
|
|
||||||
if ((typeof j === 'string') && j[0] === 'r') {
|
|
||||||
this._value = Base.decode_check(Base.VER_ACCOUNT_ID, j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._update();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
// XXX Json form should allow 0 and 1, C++ doesn't currently allow it.
|
|
||||||
UInt160.prototype.to_json = function(opts = {}) {
|
|
||||||
|
|
||||||
if (this.is_valid()) {
|
|
||||||
// If this value has a type, return a Base58 encoded string.
|
|
||||||
if (typeof this._version_byte === 'number') {
|
|
||||||
let output = Base.encode_check(this._version_byte, this.to_bytes());
|
|
||||||
|
|
||||||
if (opts.gateways && output in opts.gateways) {
|
|
||||||
output = opts.gateways[output];
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
return this.to_hex();
|
|
||||||
}
|
|
||||||
return NaN;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.UInt160 = UInt160;
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const utils = require('./utils');
|
|
||||||
const extend = require('extend');
|
|
||||||
const UInt = require('./uint').UInt;
|
|
||||||
|
|
||||||
//
|
|
||||||
// UInt256 support
|
|
||||||
//
|
|
||||||
|
|
||||||
const UInt256 = extend(function() {
|
|
||||||
this._value = NaN;
|
|
||||||
}, UInt);
|
|
||||||
|
|
||||||
UInt256.width = 32;
|
|
||||||
UInt256.prototype = Object.create(extend({}, UInt.prototype));
|
|
||||||
UInt256.prototype.constructor = UInt256;
|
|
||||||
|
|
||||||
const HEX_ZERO = UInt256.HEX_ZERO = '00000000000000000000000000000000' +
|
|
||||||
'00000000000000000000000000000000';
|
|
||||||
|
|
||||||
const HEX_ONE = UInt256.HEX_ONE = '00000000000000000000000000000000' +
|
|
||||||
'00000000000000000000000000000001';
|
|
||||||
|
|
||||||
UInt256.STR_ZERO = utils.hexToString(HEX_ZERO);
|
|
||||||
UInt256.STR_ONE = utils.hexToString(HEX_ONE);
|
|
||||||
|
|
||||||
exports.UInt256 = UInt256;
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
const assert = require('assert');
|
|
||||||
const Base = require('ripple-lib').Base;
|
|
||||||
const fixtures = require('./fixtures/base58.json');
|
|
||||||
|
|
||||||
function digitArray(str) {
|
|
||||||
return str.split('').map(function(d) {
|
|
||||||
return parseInt(d, 10);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function hexToByteArray(hex) {
|
|
||||||
const byteArray = [];
|
|
||||||
for (let i = 0; i < hex.length / 2; i++) {
|
|
||||||
byteArray.push(parseInt(hex.slice(2 * i, 2 * i + 2), 16));
|
|
||||||
}
|
|
||||||
return byteArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('Base', function() {
|
|
||||||
describe('encode_check', function() {
|
|
||||||
it('0', function() {
|
|
||||||
const encoded = Base.encode_check(0, digitArray('00000000000000000000'));
|
|
||||||
assert.strictEqual(encoded, 'rrrrrrrrrrrrrrrrrrrrrhoLvTp');
|
|
||||||
});
|
|
||||||
it('1', function() {
|
|
||||||
const encoded = Base.encode_check(0, digitArray('00000000000000000001'));
|
|
||||||
assert.strictEqual(encoded, 'rrrrrrrrrrrrrrrrrrrrBZbvji');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('decode_check', function() {
|
|
||||||
it('rrrrrrrrrrrrrrrrrrrrrhoLvTp', function() {
|
|
||||||
const decoded = Base.decode_check(0, 'rrrrrrrrrrrrrrrrrrrrrhoLvTp');
|
|
||||||
assert(decoded.cmpn(0) === 0);
|
|
||||||
});
|
|
||||||
it('rrrrrrrrrrrrrrrrrrrrBZbvji', function() {
|
|
||||||
const decoded = Base.decode_check(0, 'rrrrrrrrrrrrrrrrrrrrBZbvji');
|
|
||||||
assert(decoded.cmpn(1) === 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('decode-encode identity', function() {
|
|
||||||
it('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function() {
|
|
||||||
const decoded = Base.decode('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
|
||||||
const encoded = Base.encode(decoded);
|
|
||||||
assert.strictEqual(encoded, 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('encode', function() {
|
|
||||||
it('fixtures', function() {
|
|
||||||
for (let i = 0; i < fixtures.ripple.length; i++) {
|
|
||||||
const testCase = fixtures.ripple[i];
|
|
||||||
const encoded = Base.encode(hexToByteArray(testCase.hex));
|
|
||||||
assert.strictEqual(encoded, testCase.string);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe('decode', function() {
|
|
||||||
it('fixtures', function() {
|
|
||||||
for (let i = 0; i < fixtures.ripple.length; i++) {
|
|
||||||
const testCase = fixtures.ripple[i];
|
|
||||||
const decoded = Base.decode(testCase.string);
|
|
||||||
assert.deepEqual(decoded, hexToByteArray(testCase.hex));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
var assert = require('assert');
|
|
||||||
var convertBase = require('ripple-lib').convertBase;
|
|
||||||
|
|
||||||
// Test cases from RFC-1924 (a joke RFC)
|
|
||||||
var BASE85 = ('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
||||||
+ 'abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~');
|
|
||||||
var BASE10 = BASE85.slice(0, 10);
|
|
||||||
var BASE16 = BASE85.slice(0, 16);
|
|
||||||
|
|
||||||
var DATA16 = '108000000000000000080800200C417A';
|
|
||||||
var DATA10 = '21932261930451111902915077091070067066';
|
|
||||||
var DATA85 = '4)+k&C#VzJ4br>0wv%Yp';
|
|
||||||
|
|
||||||
function encode(digitArray, encoding) {
|
|
||||||
return digitArray.map(function(i) {
|
|
||||||
return encoding.charAt(i);
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function decode(encoded, encoding) {
|
|
||||||
return encoded.split('').map(function(c) {
|
|
||||||
return encoding.indexOf(c);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertBaseEncoded(value, fromEncoding, toEncoding) {
|
|
||||||
var digitArray = decode(value, fromEncoding);
|
|
||||||
var converted = convertBase(digitArray, fromEncoding.length,
|
|
||||||
toEncoding.length);
|
|
||||||
return encode(converted, toEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('convertBase', function() {
|
|
||||||
it('DEC -> HEX', function () {
|
|
||||||
assert.strictEqual(convertBaseEncoded(DATA10, BASE10, BASE16), DATA16);
|
|
||||||
});
|
|
||||||
it('HEX -> DEC', function () {
|
|
||||||
assert.strictEqual(convertBaseEncoded(DATA16, BASE16, BASE10), DATA10);
|
|
||||||
});
|
|
||||||
it('DEC -> B85', function () {
|
|
||||||
assert.strictEqual(convertBaseEncoded(DATA10, BASE10, BASE85), DATA85);
|
|
||||||
});
|
|
||||||
it('HEX -> B85', function () {
|
|
||||||
assert.strictEqual(convertBaseEncoded(DATA16, BASE16, BASE85), DATA85);
|
|
||||||
});
|
|
||||||
it('B85 -> DEC', function () {
|
|
||||||
assert.strictEqual(convertBaseEncoded(DATA85, BASE85, BASE10), DATA10);
|
|
||||||
});
|
|
||||||
it('B85 -> HEX', function () {
|
|
||||||
assert.strictEqual(convertBaseEncoded(DATA85, BASE85, BASE16), DATA16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"value": "0.001"
|
"value": "0.001"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"paths": "[[{\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":48,\"type_hex\":\"0000000000000030\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":49,\"type_hex\":\"0000000000000031\"}]]"
|
"paths": "[[{\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\"}]]"
|
||||||
},
|
},
|
||||||
"outcome": {
|
"outcome": {
|
||||||
"result": "tesSUCCESS",
|
"result": "tesSUCCESS",
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
"value": "0.001"
|
"value": "0.001"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"paths": "[[{\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":48,\"type_hex\":\"0000000000000030\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"type\":49,\"type_hex\":\"0000000000000031\"}]]"
|
"paths": "[[{\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\"},{\"account\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"issuer\":\"rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo\",\"currency\":\"USD\"}]]"
|
||||||
},
|
},
|
||||||
"outcome": {
|
"outcome": {
|
||||||
"result": "tesSUCCESS",
|
"result": "tesSUCCESS",
|
||||||
|
|||||||
6
test/fixtures/api/rippled/account-tx.js
vendored
6
test/fixtures/api/rippled/account-tx.js
vendored
@@ -3,9 +3,9 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const hashes = require('../../hashes');
|
const hashes = require('../../hashes');
|
||||||
const addresses = require('../../addresses');
|
const addresses = require('../../addresses');
|
||||||
const SerializedObject = require('ripple-lib').SerializedObject;
|
|
||||||
const AccountSet = require('./tx/account-set.json');
|
const AccountSet = require('./tx/account-set.json');
|
||||||
const NotFound = require('./tx/not-found.json');
|
const NotFound = require('./tx/not-found.json');
|
||||||
|
const binary = require('ripple-binary-codec');
|
||||||
|
|
||||||
module.exports = function(request, options = {}) {
|
module.exports = function(request, options = {}) {
|
||||||
_.defaults(options, {
|
_.defaults(options, {
|
||||||
@@ -229,8 +229,8 @@ module.exports = function(request, options = {}) {
|
|||||||
transactions: [
|
transactions: [
|
||||||
{
|
{
|
||||||
ledger_index: 348860 - Number(marker || 100),
|
ledger_index: 348860 - Number(marker || 100),
|
||||||
tx_blob: SerializedObject.from_json(tx).to_hex(),
|
tx_blob: binary.encode(tx),
|
||||||
meta: SerializedObject.from_json(meta).to_hex(),
|
meta: binary.encode(meta),
|
||||||
validated: options.validated
|
validated: options.validated
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
114
test/fixtures/binary-account-transaction.json
vendored
114
test/fixtures/binary-account-transaction.json
vendored
@@ -368,84 +368,56 @@
|
|||||||
"Paths": [
|
"Paths": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -697,84 +669,56 @@
|
|||||||
"Paths": [
|
"Paths": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -794,4 +738,4 @@
|
|||||||
"validated": true
|
"validated": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
138
test/fixtures/binary-transaction.json
vendored
138
test/fixtures/binary-transaction.json
vendored
@@ -104,61 +104,41 @@
|
|||||||
"Paths": [
|
"Paths": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rP9Lt7SZUEErkXAXyggceibTCEYbfSyx6n",
|
"account": "rP9Lt7SZUEErkXAXyggceibTCEYbfSyx6n"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rwBWBFZrbLzHoe3PhwWYv89iHJdxAFrxcB",
|
"account": "rwBWBFZrbLzHoe3PhwWYv89iHJdxAFrxcB"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -405,84 +385,56 @@
|
|||||||
"Paths": [
|
"Paths": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "USD",
|
"currency": "USD",
|
||||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 48,
|
|
||||||
"type_hex": "0000000000000030"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -871,60 +823,40 @@
|
|||||||
"Paths": [
|
"Paths": [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rULnR9YhAkj9HrcxAcudzBhaXRSqT7zJkq",
|
"account": "rULnR9YhAkj9HrcxAcudzBhaXRSqT7zJkq"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"account": "rP5ShE8dGBH6hHtNvRESdMceen36XFBQmh",
|
"account": "rP5ShE8dGBH6hHtNvRESdMceen36XFBQmh"
|
||||||
"type": 1,
|
|
||||||
"type_hex": "0000000000000001"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"currency": "XRP",
|
"currency": "XRP"
|
||||||
"type": 16,
|
|
||||||
"type_hex": "0000000000000010"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
@@ -1225,4 +1157,4 @@
|
|||||||
"validated": true
|
"validated": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
test/fixtures/orderbook.js
vendored
8
test/fixtures/orderbook.js
vendored
@@ -5,9 +5,8 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const addresses = require('./addresses');
|
const addresses = require('./addresses');
|
||||||
const Meta = require('ripple-lib').Meta;
|
const Meta = require('ripple-lib').Meta;
|
||||||
const SerializedObject = require('ripple-lib').SerializedObject;
|
|
||||||
const Types = require('ripple-lib').types;
|
|
||||||
const IOUValue = require('ripple-lib-value').IOUValue;
|
const IOUValue = require('ripple-lib-value').IOUValue;
|
||||||
|
const binary = require('ripple-binary-codec');
|
||||||
|
|
||||||
module.exports.FIAT_BALANCE = '10';
|
module.exports.FIAT_BALANCE = '10';
|
||||||
module.exports.NATIVE_BALANCE = '55';
|
module.exports.NATIVE_BALANCE = '55';
|
||||||
@@ -824,10 +823,7 @@ module.exports.transactionWithCreatedOffer = function(options) {
|
|||||||
const takerPays = new IOUValue(module.exports.TAKER_PAYS);
|
const takerPays = new IOUValue(module.exports.TAKER_PAYS);
|
||||||
const quality = takerPays.divide(takerGets);
|
const quality = takerPays.divide(takerGets);
|
||||||
|
|
||||||
const so = new SerializedObject();
|
const BookDirectory = binary.encodeQuality(quality.toString());
|
||||||
Types.Quality.serialize(so, quality);
|
|
||||||
|
|
||||||
const BookDirectory = so.to_hex();
|
|
||||||
|
|
||||||
const meta = new Meta({
|
const meta = new Meta({
|
||||||
AffectedNodes: [
|
AffectedNodes: [
|
||||||
|
|||||||
@@ -1,352 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/* eslint-disable max-len*/
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const lodash = require('lodash');
|
|
||||||
const SerializedObject = require('ripple-lib').SerializedObject;
|
|
||||||
const Amount = require('ripple-lib').Amount;
|
|
||||||
const sjclcodec = require('sjcl-codec');
|
|
||||||
|
|
||||||
// Shortcuts
|
|
||||||
const hex = sjclcodec.hex;
|
|
||||||
const utf8 = sjclcodec.utf8String;
|
|
||||||
|
|
||||||
describe('Serialized object', function() {
|
|
||||||
|
|
||||||
function convertStringToHex(string) {
|
|
||||||
return hex.fromBits(utf8.toBits(string)).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('#from_json(v).to_json() == v', function() {
|
|
||||||
it('outputs same as passed to from_json', function() {
|
|
||||||
const input_json = {
|
|
||||||
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Amount: '274579388',
|
|
||||||
Destination: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Fee: '15',
|
|
||||||
Flags: 0,
|
|
||||||
Paths: [[
|
|
||||||
{
|
|
||||||
account: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
|
||||||
currency: 'USD',
|
|
||||||
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
|
||||||
type: 49,
|
|
||||||
type_hex: '0000000000000031'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
currency: 'XRP',
|
|
||||||
type: 16,
|
|
||||||
type_hex: '0000000000000010'
|
|
||||||
}
|
|
||||||
]],
|
|
||||||
SendMax: {
|
|
||||||
currency: 'USD',
|
|
||||||
issuer: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
value: '2.74579388'
|
|
||||||
},
|
|
||||||
Sequence: 351,
|
|
||||||
SigningPubKey: '02854B06CE8F3E65323F89260E9E19B33DA3E01B30EA4CA172612DE77973FAC58A',
|
|
||||||
TransactionType: 'Payment',
|
|
||||||
TxnSignature: '30450221009DA3A42DD25E3B22EC45AD8BA8FC7A954264264A816D300B2DF69F814D7D4DD2022072C9627F97EEC6DA13DE841E06E2CD985EF06A0FBB15DDBF0800D0730C8986BF'
|
|
||||||
};
|
|
||||||
const output_json = SerializedObject.from_json(input_json).to_json();
|
|
||||||
assert.deepEqual(input_json, output_json);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#from_json(v).to_json() == v -- invalid amount', function() {
|
|
||||||
it('outputs same as passed to from_json', function() {
|
|
||||||
const input_json = {
|
|
||||||
Account: 'rUR9gTCcrUY9fMkz9rwcM9urPREh3LKXoW',
|
|
||||||
Fee: '10',
|
|
||||||
Flags: 0,
|
|
||||||
Sequence: 65,
|
|
||||||
SigningPubKey: '033D0B1FB932E0408C119107483190B61561DCE8529E29CB5D1C69128DA54DA715',
|
|
||||||
TakerGets: '2188313981504612096',
|
|
||||||
TakerPays: {
|
|
||||||
currency: 'USD',
|
|
||||||
issuer: 'r9rp9MUFRJVCVLRm3MTmUvSPNBSL3BuEFx',
|
|
||||||
value: '99999999999'
|
|
||||||
},
|
|
||||||
TransactionType: 'OfferCreate',
|
|
||||||
TxnSignature: '304602210085C6AE945643150E6D450CF796E45D74FB24B4E03E964A29CC6AFFEB346C77C80221009BE1B6678CF6C2E61F8F2696144C75AFAF66DF4FC0733DF9118EDEFEEFE33243'
|
|
||||||
};
|
|
||||||
|
|
||||||
assert.throws(function() {
|
|
||||||
SerializedObject.from_json(input_json).to_json();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#from_json(v).to_json() == v -- invalid amount, strict_mode = false', function() {
|
|
||||||
it('outputs same as passed to from_json', function() {
|
|
||||||
const input_json = {
|
|
||||||
Account: 'rUR9gTCcrUY9fMkz9rwcM9urPREh3LKXoW',
|
|
||||||
Fee: '10',
|
|
||||||
Flags: 0,
|
|
||||||
Sequence: 65,
|
|
||||||
SigningPubKey: '033D0B1FB932E0408C119107483190B61561DCE8529E29CB5D1C69128DA54DA715',
|
|
||||||
TakerGets: '2188313981504612096',
|
|
||||||
TakerPays: {
|
|
||||||
currency: 'USD',
|
|
||||||
issuer: 'r9rp9MUFRJVCVLRm3MTmUvSPNBSL3BuEFx',
|
|
||||||
value: '99999999999'
|
|
||||||
},
|
|
||||||
TransactionType: 'OfferCreate',
|
|
||||||
TxnSignature: 'FFFFFF210085C6AE945643150E6D450CF796E45D74FB24B4E03E964A29CC6AFFEB346C77C80221009BE1B6678CF6C2E61F8F2696144C75AFAF66DF4FC0733DF9118EDEFEEFE33243'
|
|
||||||
};
|
|
||||||
|
|
||||||
const strictMode = Amount.strict_mode;
|
|
||||||
Amount.strict_mode = false;
|
|
||||||
const output_json = SerializedObject.from_json(input_json).to_json();
|
|
||||||
assert.deepEqual(input_json, output_json);
|
|
||||||
Amount.strict_mode = strictMode;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#from_json', function() {
|
|
||||||
it('understands TransactionType as a Number', function() {
|
|
||||||
const input_json = {
|
|
||||||
// no non required fields
|
|
||||||
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Amount: '274579388',
|
|
||||||
Destination: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Fee: '15',
|
|
||||||
Sequence: 351,
|
|
||||||
SigningPubKey: '02',// VL field ;)
|
|
||||||
TransactionType: 0 //
|
|
||||||
};
|
|
||||||
const output_json = SerializedObject.from_json(input_json).to_json();
|
|
||||||
|
|
||||||
assert.equal(0, input_json.TransactionType);
|
|
||||||
assert.equal('Payment', output_json.TransactionType);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('understands LedgerEntryType as a Number', function() {
|
|
||||||
const input_json = {
|
|
||||||
// no, non required fields
|
|
||||||
LedgerEntryType: 100,
|
|
||||||
Flags: 0,
|
|
||||||
Indexes: [],
|
|
||||||
RootIndex: '000360186E008422E06B72D5B275E29EE3BE9D87A370F424E0E7BF613C465909'
|
|
||||||
};
|
|
||||||
|
|
||||||
const output_json = SerializedObject.from_json(input_json).to_json();
|
|
||||||
assert.equal(100, input_json.LedgerEntryType);
|
|
||||||
assert.equal('DirectoryNode', output_json.LedgerEntryType);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('checks for missing required fields', function() {
|
|
||||||
const input_json = {
|
|
||||||
TransactionType: 'Payment',
|
|
||||||
// no non required fields
|
|
||||||
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Amount: '274579388',
|
|
||||||
Destination: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Fee: '15',
|
|
||||||
Sequence: 351,
|
|
||||||
SigningPubKey: '02'
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(input_json).slice(1).forEach(function(k) {
|
|
||||||
const bad_json = lodash.merge({}, input_json);
|
|
||||||
delete bad_json[k];
|
|
||||||
|
|
||||||
assert.strictEqual(bad_json[k], undefined);
|
|
||||||
assert.throws(function() {
|
|
||||||
SerializedObject.from_json(bad_json);
|
|
||||||
}, new RegExp('Payment is missing fields: \\["' + k + '"\\]'));
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('checks for unknown fields', function() {
|
|
||||||
const input_json = {
|
|
||||||
TransactionType: 'Payment',
|
|
||||||
// no non required fields
|
|
||||||
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Amount: '274579388',
|
|
||||||
Destination: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Fee: '15',
|
|
||||||
Sequence: 351,
|
|
||||||
SigningPubKey: '02'
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(input_json).slice(1).forEach(function(k) {
|
|
||||||
const bad_json = lodash.merge({}, input_json);
|
|
||||||
bad_json[k + 'z'] = bad_json[k];
|
|
||||||
|
|
||||||
assert.throws(function() {
|
|
||||||
SerializedObject.from_json(bad_json);
|
|
||||||
}, new RegExp('Payment has unknown fields: \\["' + k + 'z"\\]'));
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Format validation', function() {
|
|
||||||
// Peercover actually had a problem submitting transactions without a `Fee`
|
|
||||||
// and rippled was only informing of 'transaction is invalid'
|
|
||||||
it('should throw an Error when there is a missing field', function() {
|
|
||||||
const input_json = {
|
|
||||||
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Amount: '274579388',
|
|
||||||
Destination: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
|
||||||
Sequence: 351,
|
|
||||||
SigningPubKey: '02854B06CE8F3E65323F89260E9E19B33DA3E01B30EA4CA172612DE77973FAC58A',
|
|
||||||
TransactionType: 'Payment',
|
|
||||||
TxnSignature: '30450221009DA3A42DD25E3B22EC45AD8BA8FC7A954264264A816D300B2DF69F814D7D4DD2022072C9627F97EEC6DA13DE841E06E2CD985EF06A0FBB15DDBF0800D0730C8986BF'
|
|
||||||
};
|
|
||||||
assert.throws(
|
|
||||||
function() {
|
|
||||||
SerializedObject.from_json(input_json);
|
|
||||||
},
|
|
||||||
/Payment is missing fields: \["Fee"\]/
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Memos', function() {
|
|
||||||
let input_json;
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
input_json = {
|
|
||||||
'Flags': 2147483648,
|
|
||||||
'TransactionType': 'Payment',
|
|
||||||
'Account': 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
|
|
||||||
'Amount': '1',
|
|
||||||
'Destination': 'radqi6ppXFxVhJdjzaATRBxdrPcVTf1Ung',
|
|
||||||
'Sequence': 281,
|
|
||||||
'SigningPubKey': '03D642E6457B8AB4D140E2C66EB4C484FAFB1BF267CB578EC4815FE6CD06379C51',
|
|
||||||
'Fee': '12000',
|
|
||||||
'LastLedgerSequence': 10074214,
|
|
||||||
'TxnSignature': '304402201180636F2CE215CE97A29CD302618FAE60D63EBFC8903DE17A356E857A449C430220290F4A54F9DE4AC79034C8BEA5F1F8757F7505F1A6FF04D2E19B6D62E867256B'
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should serialize and parse - full memo, all strings text/plain ', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
Memo: {
|
|
||||||
MemoType: '74657374',
|
|
||||||
MemoFormat: '74657874',
|
|
||||||
MemoData: '736F6D652064617461'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const so = SerializedObject.from_json(input_json).to_json();
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_format = 'text';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_data = 'some data';
|
|
||||||
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
|
||||||
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('text');
|
|
||||||
input_json.Memos[0].Memo.MemoData = convertStringToHex('some data');
|
|
||||||
|
|
||||||
assert.deepEqual(so, input_json);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should serialize and parse - full memo, all strings, invalid MemoFormat', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
'Memo':
|
|
||||||
{
|
|
||||||
MemoType: '74657374',
|
|
||||||
MemoFormat: '6170706C69636174696F6E2F6A736F6E',
|
|
||||||
MemoData: '736F6D652064617461'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const so = SerializedObject.from_json(input_json).to_json();
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_format = 'application/json';
|
|
||||||
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
|
||||||
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('application/json');
|
|
||||||
input_json.Memos[0].Memo.MemoData = convertStringToHex('some data');
|
|
||||||
|
|
||||||
assert.deepEqual(so, input_json);
|
|
||||||
assert.strictEqual(input_json.Memos[0].Memo.parsed_memo_data, undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should serialize and parse - full memo, json data, valid MemoFormat, ignored field', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
Memo: {
|
|
||||||
MemoType: '74657374',
|
|
||||||
MemoFormat: '6A736F6E',
|
|
||||||
ignored: 'ignored',
|
|
||||||
MemoData: '7B22737472696E67223A22736F6D655F737472696E67222C22626F6F6C65616E223A747275657D'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const so = SerializedObject.from_json(input_json).to_json();
|
|
||||||
delete input_json.Memos[0].Memo.ignored;
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_format = 'json';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_data = {
|
|
||||||
'string': 'some_string',
|
|
||||||
'boolean': true
|
|
||||||
};
|
|
||||||
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
|
||||||
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('json');
|
|
||||||
input_json.Memos[0].Memo.MemoData = convertStringToHex(JSON.stringify(
|
|
||||||
{
|
|
||||||
'string': 'some_string',
|
|
||||||
'boolean': true
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
assert.deepEqual(so, input_json);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error - invalid Memo field', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
Memo: {
|
|
||||||
MemoType: '74657374',
|
|
||||||
MemoField: '6A736F6E',
|
|
||||||
MemoData: '7B22737472696E67223A22736F6D655F737472696E67222C22626F6F6C65616E223A747275657D'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
assert.throws(function() {
|
|
||||||
SerializedObject.from_json(input_json);
|
|
||||||
}, /^Error: JSON contains unknown field: "MemoField" \(Memo\) \(Memos\)/);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should serialize json with memo - match hex output', function() {
|
|
||||||
input_json = {
|
|
||||||
Flags: 2147483648,
|
|
||||||
TransactionType: 'Payment',
|
|
||||||
Account: 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
|
|
||||||
Amount: '1',
|
|
||||||
Destination: 'radqi6ppXFxVhJdjzaATRBxdrPcVTf1Ung',
|
|
||||||
Memos: [
|
|
||||||
{
|
|
||||||
Memo: {
|
|
||||||
MemoType: '696D616765'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
Sequence: 294,
|
|
||||||
SigningPubKey: '03D642E6457B8AB4D140E2C66EB4C484FAFB1BF267CB578EC4815FE6CD06379C51',
|
|
||||||
Fee: '12000',
|
|
||||||
LastLedgerSequence: 10404607,
|
|
||||||
TxnSignature: '304402206B53EDFA6EFCF6FE5BA76C81BABB60A3B55E9DE8A1462DEDC5F387879575E498022015AE7B59AA49E735D7F2E252802C4406CD00689BCE5057C477FE979D38D2DAC9'
|
|
||||||
};
|
|
||||||
|
|
||||||
const serializedHex = '12000022800000002400000126201B009EC2FF614000000000000001684000000000002EE0732103D642E6457B8AB4D140E2C66EB4C484FAFB1BF267CB578EC4815FE6CD06379C517446304402206B53EDFA6EFCF6FE5BA76C81BABB60A3B55E9DE8A1462DEDC5F387879575E498022015AE7B59AA49E735D7F2E252802C4406CD00689BCE5057C477FE979D38D2DAC9811426C4CFB3BD05A9AA23936F2E81634C66A9820C9483143DD06317D19C6110CAFF150AE528F58843BE2CA1F9EA7C05696D616765E1F1';
|
|
||||||
assert.strictEqual(SerializedObject.from_json(input_json).to_hex(), serializedHex);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,8 @@ const ws = require('ws');
|
|||||||
const lodash = require('lodash');
|
const lodash = require('lodash');
|
||||||
const assert = require('assert-diff');
|
const assert = require('assert-diff');
|
||||||
const Remote = require('ripple-lib').Remote;
|
const Remote = require('ripple-lib').Remote;
|
||||||
const SerializedObject = require('ripple-lib').SerializedObject;
|
const binary = require('ripple-binary-codec');
|
||||||
|
const utils = require('ripple-lib').utils;
|
||||||
const Transaction = require('ripple-lib').Transaction;
|
const Transaction = require('ripple-lib').Transaction;
|
||||||
const TransactionManager = require('ripple-lib')._test.TransactionManager;
|
const TransactionManager = require('ripple-lib')._test.TransactionManager;
|
||||||
|
|
||||||
@@ -335,11 +336,12 @@ describe('TransactionManager', function() {
|
|||||||
|
|
||||||
const binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
const binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
||||||
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
||||||
tx_blob: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.tx).to_hex(),
|
tx_blob: binary.encode(ACCOUNT_TX_TRANSACTION.tx),
|
||||||
meta: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.meta).to_hex()
|
meta: binary.encode(ACCOUNT_TX_TRANSACTION.meta)
|
||||||
});
|
});
|
||||||
|
|
||||||
const hash = new SerializedObject(binaryTx.tx_blob).hash(0x54584E00).to_hex();
|
const prefix = (0x54584E00).toString(16);
|
||||||
|
const hash = utils.sha512half(new Buffer(prefix + binaryTx.tx_blob, 'hex'));
|
||||||
|
|
||||||
transaction.addId(hash);
|
transaction.addId(hash);
|
||||||
|
|
||||||
@@ -364,8 +366,8 @@ describe('TransactionManager', function() {
|
|||||||
|
|
||||||
const binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
const binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
||||||
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
||||||
tx_blob: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.tx).to_hex(),
|
tx_blob: binary.encode(ACCOUNT_TX_TRANSACTION.tx),
|
||||||
meta: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.meta).to_hex()
|
meta: binary.encode(ACCOUNT_TX_TRANSACTION.meta)
|
||||||
});
|
});
|
||||||
|
|
||||||
transactionManager._request = function() {
|
transactionManager._request = function() {
|
||||||
@@ -417,9 +419,8 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.once('request_submit', function(m, req) {
|
rippled.once('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
assert.strictEqual(binary.decode(m.tx_blob).Sequence,
|
||||||
assert.strictEqual(new SerializedObject(m.tx_blob).to_json().Sequence,
|
|
||||||
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
req.sendResponse(SUBMIT_RESPONSE, {id: m.id});
|
req.sendResponse(SUBMIT_RESPONSE, {id: m.id});
|
||||||
@@ -457,9 +458,8 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.once('request_submit', function(m, req) {
|
rippled.once('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
assert.strictEqual(binary.decode(m.tx_blob).Sequence,
|
||||||
assert.strictEqual(new SerializedObject(m.tx_blob).to_json().Sequence,
|
|
||||||
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
req.sendResponse(SUBMIT_TEC_RESPONSE, {id: m.id});
|
req.sendResponse(SUBMIT_TEC_RESPONSE, {id: m.id});
|
||||||
@@ -500,7 +500,7 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.on('request_submit', function(m, req) {
|
rippled.on('request_submit', function(m, req) {
|
||||||
const deserialized = new SerializedObject(m.tx_blob).to_json();
|
const deserialized = binary.decode(m.tx_blob);
|
||||||
|
|
||||||
switch (deserialized.TransactionType) {
|
switch (deserialized.TransactionType) {
|
||||||
case 'Payment':
|
case 'Payment':
|
||||||
@@ -570,8 +570,7 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.on('request_submit', function(m, req) {
|
rippled.on('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
req.sendResponse(SUBMIT_TEF_RESPONSE, {id: m.id});
|
req.sendResponse(SUBMIT_TEF_RESPONSE, {id: m.id});
|
||||||
});
|
});
|
||||||
@@ -630,9 +629,8 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.on('request_submit', function(m, req) {
|
rippled.on('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
assert.strictEqual(binary.decode(m.tx_blob).Sequence,
|
||||||
assert.strictEqual(new SerializedObject(m.tx_blob).to_json().Sequence,
|
|
||||||
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
|
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
|
||||||
@@ -737,9 +735,8 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.on('request_submit', function(m, req) {
|
rippled.on('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
assert.strictEqual(binary.decode(m.tx_blob).Sequence,
|
||||||
assert.strictEqual(new SerializedObject(m.tx_blob).to_json().Sequence,
|
|
||||||
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
|
||||||
@@ -797,9 +794,8 @@ describe('TransactionManager', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
rippled.on('request_submit', function(m, req) {
|
rippled.on('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
assert.strictEqual(binary.decode(m.tx_blob).Sequence,
|
||||||
assert.strictEqual(new SerializedObject(m.tx_blob).to_json().Sequence,
|
|
||||||
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
|
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
|
||||||
@@ -867,9 +863,8 @@ describe('TransactionManager', function() {
|
|||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
rippled.on('request_submit', function(m, req) {
|
rippled.on('request_submit', function(m, req) {
|
||||||
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
assert.strictEqual(m.tx_blob, binary.encode(transaction.tx_json));
|
||||||
transaction.tx_json).to_hex());
|
assert.strictEqual(binary.decode(m.tx_blob).Sequence,
|
||||||
assert.strictEqual(new SerializedObject(m.tx_blob).to_json().Sequence,
|
|
||||||
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
ACCOUNT_INFO_RESPONSE.result.account_data.Sequence);
|
||||||
assert.strictEqual(transactionManager.getPending().length(), 1);
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
var assert = require('assert');
|
'use strict';
|
||||||
var Transaction = require('ripple-lib').Transaction;
|
const assert = require('assert');
|
||||||
var TransactionQueue = require('ripple-lib').TransactionQueue;
|
const Transaction = require('ripple-lib').Transaction;
|
||||||
|
const TransactionQueue = require('ripple-lib')._test.TransactionQueue;
|
||||||
|
|
||||||
describe('Transaction queue', function() {
|
describe('Transaction queue', function() {
|
||||||
it('Push transaction', function() {
|
it('Push transaction', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
var tx = new Transaction();
|
const tx = new Transaction();
|
||||||
|
|
||||||
queue.push(tx);
|
queue.push(tx);
|
||||||
|
|
||||||
@@ -13,8 +14,8 @@ describe('Transaction queue', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Remove transaction', function() {
|
it('Remove transaction', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
var tx = new Transaction();
|
const tx = new Transaction();
|
||||||
|
|
||||||
queue.push(tx);
|
queue.push(tx);
|
||||||
queue.remove(tx);
|
queue.remove(tx);
|
||||||
@@ -23,8 +24,8 @@ describe('Transaction queue', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Remove transaction by ID', function() {
|
it('Remove transaction by ID', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
var tx = new Transaction();
|
const tx = new Transaction();
|
||||||
|
|
||||||
queue.push(tx);
|
queue.push(tx);
|
||||||
|
|
||||||
@@ -33,32 +34,38 @@ describe('Transaction queue', function() {
|
|||||||
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'
|
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'
|
||||||
];
|
];
|
||||||
|
|
||||||
queue.remove('3A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B');
|
queue.remove(
|
||||||
|
'3A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B');
|
||||||
|
|
||||||
assert.strictEqual(queue.length(), 1);
|
assert.strictEqual(queue.length(), 1);
|
||||||
|
|
||||||
queue.remove('2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B');
|
queue.remove(
|
||||||
|
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B');
|
||||||
|
|
||||||
assert.strictEqual(queue.length(), 0);
|
assert.strictEqual(queue.length(), 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Add sequence', function() {
|
it('Add sequence', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
queue.addReceivedSequence(1);
|
queue.addReceivedSequence(1);
|
||||||
assert(queue.hasSequence(1));
|
assert(queue.hasSequence(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Add ID', function() {
|
it('Add ID', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
var tx = new Transaction();
|
const tx = new Transaction();
|
||||||
queue.addReceivedId('1A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B', tx);
|
queue.addReceivedId(
|
||||||
assert.strictEqual(queue.getReceived('2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), void(0));
|
'1A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B', tx);
|
||||||
assert.strictEqual(queue.getReceived('1A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), tx);
|
assert.strictEqual(queue.getReceived(
|
||||||
|
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'),
|
||||||
|
undefined);
|
||||||
|
assert.strictEqual(queue.getReceived(
|
||||||
|
'1A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Get submission', function() {
|
it('Get submission', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
var tx = new Transaction();
|
const tx = new Transaction();
|
||||||
|
|
||||||
queue.push(tx);
|
queue.push(tx);
|
||||||
|
|
||||||
@@ -67,16 +74,20 @@ describe('Transaction queue', function() {
|
|||||||
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'
|
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'
|
||||||
];
|
];
|
||||||
|
|
||||||
assert.strictEqual(queue.getSubmission('1A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), tx);
|
assert.strictEqual(queue.getSubmission(
|
||||||
assert.strictEqual(queue.getSubmission('2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), tx);
|
'1A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), tx);
|
||||||
assert.strictEqual(queue.getSubmission('3A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), void(0));
|
assert.strictEqual(queue.getSubmission(
|
||||||
|
'2A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'), tx);
|
||||||
|
assert.strictEqual(queue.getSubmission(
|
||||||
|
'3A4DEBF37496464145AA301F0AA77712E3A2BFE3480D24C3584663F800B85B5B'),
|
||||||
|
undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Iterate over queue', function() {
|
it('Iterate over queue', function() {
|
||||||
var queue = new TransactionQueue();
|
const queue = new TransactionQueue();
|
||||||
var count = 10;
|
let count = 10;
|
||||||
|
|
||||||
for (var i=0; i<count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
queue.push(new Transaction());
|
queue.push(new Transaction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
const assert = require('assert-diff');
|
const assert = require('assert-diff');
|
||||||
const lodash = require('lodash');
|
const lodash = require('lodash');
|
||||||
const addresses = require('./fixtures/addresses');
|
const addresses = require('./fixtures/addresses');
|
||||||
const ripple = require('ripple-lib');
|
|
||||||
const Transaction = require('ripple-lib').Transaction;
|
const Transaction = require('ripple-lib').Transaction;
|
||||||
const TransactionQueue = require('ripple-lib').TransactionQueue;
|
const TransactionQueue = require('ripple-lib')._test.TransactionQueue;
|
||||||
const Remote = require('ripple-lib').Remote;
|
const Remote = require('ripple-lib').Remote;
|
||||||
const Server = require('ripple-lib').Server;
|
const Server = require('ripple-lib').Server;
|
||||||
const {decodeAddress} = require('ripple-address-codec');
|
const {decodeAddress} = require('ripple-address-codec');
|
||||||
|
const binary = require('ripple-binary-codec');
|
||||||
|
|
||||||
const transactionResult = {
|
const transactionResult = {
|
||||||
engine_result: 'tesSUCCESS',
|
engine_result: 'tesSUCCESS',
|
||||||
@@ -2255,13 +2255,14 @@ describe('Transaction', function() {
|
|||||||
const a1 = 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK';
|
const a1 = 'rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK';
|
||||||
const d1 = transaction.multiSigningData(a1);
|
const d1 = transaction.multiSigningData(a1);
|
||||||
|
|
||||||
const tbytes = ripple.SerializedObject.from_json(
|
const txHex = binary.encode(
|
||||||
lodash.merge(transaction.tx_json, {SigningPubKey: ''})).buffer;
|
lodash.merge(transaction.tx_json, {SigningPubKey: ''}));
|
||||||
const abytes = decodeAddress(a1);
|
const abytes = decodeAddress(a1);
|
||||||
const prefix = require('ripple-lib')._test.HashPrefixes.HASH_TX_MULTISIGN_BYTES;
|
const prefix = require('ripple-lib')._test.HashPrefixes.HASH_TX_MULTISIGN_BYTES;
|
||||||
|
|
||||||
assert.deepEqual(new Buffer(d1, 'hex'),
|
assert.deepEqual(new Buffer(d1, 'hex'),
|
||||||
new Buffer(prefix.concat(tbytes, abytes)));
|
Buffer.concat([new Buffer(prefix), new Buffer(txHex, 'hex'),
|
||||||
|
new Buffer(abytes)]));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Multisign', function() {
|
it('Multisign', function() {
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/* eslint-disable max-len */
|
|
||||||
const _ = require('lodash');
|
|
||||||
const assert = require('assert-diff');
|
|
||||||
const lodash = require('lodash');
|
|
||||||
const ripple = require('ripple-lib')._test;
|
|
||||||
const fixtures = require('./fixtures/uint');
|
|
||||||
const UInt160 = ripple.UInt160;
|
|
||||||
|
|
||||||
function resultError(test, result) {
|
|
||||||
function type(e) {
|
|
||||||
return Object.prototype.toString.call(e);
|
|
||||||
}
|
|
||||||
return `Expected ${type(test.input)}: ${test.input} to yield ${type(test.expected)}: ${test.expected === 'null' ? NaN : test.expected}. Actual: ${type(result)}: ${result}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeTests(uIntType) {
|
|
||||||
describe(uIntType, function() {
|
|
||||||
const rippleType = ripple[uIntType];
|
|
||||||
const tests = fixtures[uIntType];
|
|
||||||
|
|
||||||
it('from_json().to_json()', function() {
|
|
||||||
tests['from_json().to_json()'].forEach(function(test) {
|
|
||||||
let result = rippleType.from_json(test.input);
|
|
||||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
|
||||||
result = result.to_json();
|
|
||||||
|
|
||||||
if (test.expected === 'null') {
|
|
||||||
// XXX
|
|
||||||
// UInt160.to_json() returns NaN rather than null if input is invalid
|
|
||||||
assert.strictEqual(lodash.isNaN(result), true, resultError(test, result));
|
|
||||||
} else {
|
|
||||||
assert.strictEqual(result, test.expected, resultError(test, result));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('from_json().to_bytes()', function() {
|
|
||||||
tests['from_json().to_bytes()'].forEach(function(test) {
|
|
||||||
const result = rippleType.from_json(test.input);
|
|
||||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
|
||||||
assert.deepEqual(result.to_bytes(), test.expected, resultError(test, result));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('from_number().to_json()', function() {
|
|
||||||
tests['from_number().to_json()'].forEach(function(test) {
|
|
||||||
let result = rippleType.from_number(test.input);
|
|
||||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
|
||||||
result = result.to_json();
|
|
||||||
|
|
||||||
if (test.expected === 'null') {
|
|
||||||
// XXX
|
|
||||||
// UInt160.to_json() returns NaN rather than null if input is invalid
|
|
||||||
assert.strictEqual(lodash.isNaN(result), true, resultError(test, result));
|
|
||||||
} else {
|
|
||||||
assert.strictEqual(result, test.expected, resultError(test, result));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('from_number().to_hex()', function() {
|
|
||||||
tests['from_number().to_hex()'].forEach(function(test) {
|
|
||||||
const result = rippleType.from_number(test.input);
|
|
||||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null', `Validity check failed: ${test.input}`);
|
|
||||||
assert.strictEqual(result.to_hex(), test.expected, resultError(test, result));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('from_generic().to_*()', function() {
|
|
||||||
tests['from_generic().to_*()'].forEach(function(test) {
|
|
||||||
let result = rippleType.from_generic(test.input);
|
|
||||||
|
|
||||||
switch (test.input) {
|
|
||||||
// XXX
|
|
||||||
// from_generic() accepts these as "zero"
|
|
||||||
case 0:
|
|
||||||
case '0':
|
|
||||||
case undefined:
|
|
||||||
switch (test.outputMethod) {
|
|
||||||
case 'to_bytes':
|
|
||||||
test.expected = _.fill(Array(rippleType.width), 0);
|
|
||||||
break;
|
|
||||||
case 'to_json':
|
|
||||||
case 'to_hex':
|
|
||||||
test.expected = _.fill(Array(rippleType.width * 2), 0).join('');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.strictEqual(result.is_valid(), String(test.expected) !== 'null',
|
|
||||||
`Validity check failed: ${test.input} > ${test.expected}`);
|
|
||||||
|
|
||||||
result = result[test.outputMethod]();
|
|
||||||
|
|
||||||
if (test.expected === 'null') {
|
|
||||||
// XXX
|
|
||||||
// UInt160.to_json() returns NaN rather than null if input is invalid
|
|
||||||
assert.strictEqual(lodash.isNaN(result), true, resultError(test, result));
|
|
||||||
} else {
|
|
||||||
assert.deepEqual(result, test.expected, resultError(test, result));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
Reference in New Issue
Block a user