Merge pull request #504 from clark800/get-ledger

Add getLedger method, remove getLedgerHeader method
This commit is contained in:
Chris Clark
2015-08-18 10:01:22 -07:00
23 changed files with 269 additions and 99 deletions

View File

@@ -1,11 +1,11 @@
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"title": "getLedgerHeader", "title": "getLedger",
"type": "object", "type": "object",
"properties": { "properties": {
"accepted": {"type": "boolean"}, "accepted": {"type": "boolean"},
"closed": {"type": "boolean"}, "closed": {"type": "boolean"},
"accountHash": {"$ref": "hash256"}, "stateHash": {"$ref": "hash256"},
"closeTime": {"type": "integer", "minimum": 0}, "closeTime": {"type": "integer", "minimum": 0},
"closeTimeResolution": {"type": "integer", "minimum": 1}, "closeTimeResolution": {"type": "integer", "minimum": 1},
"closeFlags": {"type": "integer", "minimum": 0}, "closeFlags": {"type": "integer", "minimum": 0},
@@ -14,12 +14,17 @@
"parentLedgerHash": {"$ref": "hash256"}, "parentLedgerHash": {"$ref": "hash256"},
"parentCloseTime": {"type": "integer", "minimum": 0}, "parentCloseTime": {"type": "integer", "minimum": 0},
"totalDrops": {"$ref": "value"}, "totalDrops": {"$ref": "value"},
"transactionHash": {"$ref": "hash256"} "transactionHash": {"$ref": "hash256"},
"transactions": {"type": "array", "items": {"type": "object"}},
"rawTransactions": {"type": "string"},
"transactionHashes": {"type": "array", "items": {"$ref": "hash256"}},
"rawState": {"type": "string"},
"stateHashes": {"type": "array", "items": {"$ref": "hash256"}}
}, },
"required": [ "required": [
"accepted", "accepted",
"closed", "closed",
"accountHash", "stateHash",
"closeTime", "closeTime",
"closeTimeResolution", "closeTimeResolution",
"closeFlags", "closeFlags",

View File

@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "ledger-options",
"description": "Options for getLedger",
"type": "object",
"properties": {
"ledgerVersion": {"$ref": "ledgerVersion"},
"includeAllData": {"type": "boolean"},
"includeTransactions": {"type": "boolean"},
"includeState": {"type": "boolean"}
},
"additionalProperties": false
}

View File

@@ -9,7 +9,8 @@ function error(text) {
return new ValidationError(text); return new ValidationError(text);
} }
function validateAddressAndSecret(obj: {address: string, secret: string}): void { function validateAddressAndSecret(obj: {address: string, secret: string}
): void {
const address = obj.address; const address = obj.address;
const secret = obj.secret; const secret = obj.secret;
schemaValidate('address', address); schemaValidate('address', address);
@@ -73,6 +74,7 @@ module.exports = {
getOrdersOptions: _.partial(validateOptions, 'orders-options'), getOrdersOptions: _.partial(validateOptions, 'orders-options'),
getOrderbookOptions: _.partial(validateOptions, 'orders-options'), getOrderbookOptions: _.partial(validateOptions, 'orders-options'),
getTransactionOptions: _.partial(validateOptions, 'transaction-options'), getTransactionOptions: _.partial(validateOptions, 'transaction-options'),
getLedgerOptions: _.partial(validateOptions, 'ledger-options'),
options: _.partial(validateOptions, 'options'), options: _.partial(validateOptions, 'options'),
instructions: _.partial(schemaValidate, 'instructions') instructions: _.partial(schemaValidate, 'instructions')
}; };

View File

@@ -29,8 +29,8 @@ const submit = require('./transaction/submit');
const errors = require('./common').errors; const errors = require('./common').errors;
const convertExceptions = require('./common').convertExceptions; const convertExceptions = require('./common').convertExceptions;
const generateWallet = convertExceptions(common.generateWallet); const generateWallet = convertExceptions(common.generateWallet);
const getLedgerHeader = require('./ledger/ledger-header');
const computeLedgerHash = require('./offline/ledgerhash'); const computeLedgerHash = require('./offline/ledgerhash');
const getLedger = require('./ledger/ledger');
function RippleAPI(options: {}) { function RippleAPI(options: {}) {
const _options = _.assign({}, options, {automatic_resubmission: false}); const _options = _.assign({}, options, {automatic_resubmission: false});
@@ -54,7 +54,7 @@ RippleAPI.prototype = {
getOrderbook, getOrderbook,
getSettings, getSettings,
getAccountInfo, getAccountInfo,
getLedgerHeader, getLedger,
preparePayment, preparePayment,
prepareTrustline, prepareTrustline,

View File

@@ -71,7 +71,7 @@ function getAccountInfoAsync(account: string, options: AccountInfoOptions,
function getAccountInfo(account: string, options: AccountInfoOptions={} function getAccountInfo(account: string, options: AccountInfoOptions={}
): Promise<AccountInfoResponse> { ): Promise<AccountInfoResponse> {
return utils.promisify(getAccountInfoAsync.bind(this))(account, options); return utils.promisify(getAccountInfoAsync).call(this, account, options);
} }
module.exports = getAccountInfo; module.exports = getAccountInfo;

View File

@@ -25,7 +25,7 @@ function formatBalances(balances) {
} }
function getTrustlinesAsync(account, options, callback) { function getTrustlinesAsync(account, options, callback) {
getTrustlines.bind(this)(account, options) getTrustlines.call(this, account, options)
.then(data => callback(null, data)) .then(data => callback(null, data))
.catch(callback); .catch(callback);
} }
@@ -43,7 +43,7 @@ function getBalancesAsync(account, options, callback) {
} }
function getBalances(account: string, options={}) { function getBalances(account: string, options={}) {
return utils.promisify(getBalancesAsync.bind(this))(account, options); return utils.promisify(getBalancesAsync).call(this, account, options);
} }
module.exports = getBalances; module.exports = getBalances;

View File

@@ -1,42 +0,0 @@
/* @flow */
'use strict';
const utils = require('./utils');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
function formatLedgerHeader(response) {
const header = response.ledger;
return {
accepted: header.accepted,
closed: header.closed,
accountHash: header.account_hash,
closeTime: header.close_time,
closeTimeResolution: header.close_time_resolution,
closeFlags: header.close_flags,
ledgerHash: header.hash || header.ledger_hash,
ledgerVersion: parseInt(header.ledger_index || header.seqNum, 10),
parentLedgerHash: header.parent_hash,
parentCloseTime: header.parent_close_time,
totalDrops: header.total_coins || header.totalCoins,
transactionHash: header.transaction_hash
};
}
function getLedgerHeaderAsync(ledgerVersion, callback) {
if (ledgerVersion) {
validate.ledgerVersion(ledgerVersion);
}
const request = {
ledger: ledgerVersion || 'validated'
};
this.remote.requestLedger(request,
composeAsync(formatLedgerHeader, callback));
}
function getLedgerHeader(ledgerVersion?: number) {
return utils.promisify(getLedgerHeaderAsync.bind(this))(ledgerVersion);
}
module.exports = getLedgerHeader;

26
src/api/ledger/ledger.js Normal file
View File

@@ -0,0 +1,26 @@
/* @flow */
'use strict';
const utils = require('./utils');
const validate = utils.common.validate;
const composeAsync = utils.common.composeAsync;
const parseLedger = require('./parse/ledger');
function getLedgerAsync(options, callback) {
validate.getLedgerOptions(options);
const request = {
ledger: options.ledgerVersion || 'validated',
expand: options.includeAllData,
transactions: options.includeTransactions,
accounts: options.includeState
};
this.remote.requestLedger(request,
composeAsync(response => parseLedger(response.ledger), callback));
}
function getLedger(options={}) {
return utils.promisify(getLedgerAsync).call(this, options);
}
module.exports = getLedger;

View File

@@ -10,7 +10,8 @@ const composeAsync = utils.common.composeAsync;
// account is to specify a "perspective", which affects which unfunded offers // account is to specify a "perspective", which affects which unfunded offers
// are returned // are returned
function getBookOffers(remote, account, ledgerVersion, limit, function getBookOffers(remote, account, ledgerVersion, limit,
takerGets, takerPays, callback) { takerGets, takerPays, callback
) {
remote.requestBookOffers(utils.renameCounterpartyToIssuerInOrder({ remote.requestBookOffers(utils.renameCounterpartyToIssuerInOrder({
taker_gets: takerGets, taker_gets: takerGets,
taker_pays: takerPays, taker_pays: takerPays,
@@ -77,7 +78,7 @@ function getOrderbookAsync(account, orderbook, options, callback) {
} }
function getOrderbook(account: string, orderbook: Object, options={}) { function getOrderbook(account: string, orderbook: Object, options={}) {
return utils.promisify(getOrderbookAsync.bind(this))( return utils.promisify(getOrderbookAsync).call(this,
account, orderbook, options); account, orderbook, options);
} }

View File

@@ -7,7 +7,8 @@ const composeAsync = utils.common.composeAsync;
const parseAccountOrder = require('./parse/account-order'); const parseAccountOrder = require('./parse/account-order');
function requestAccountOffers(remote, address, ledgerVersion, options, function requestAccountOffers(remote, address, ledgerVersion, options,
marker, limit, callback) { marker, limit, callback
) {
remote.requestAccountOffers({ remote.requestAccountOffers({
account: address, account: address,
marker: marker, marker: marker,
@@ -34,7 +35,7 @@ function getOrdersAsync(account, options, callback) {
} }
function getOrders(account: string, options={}) { function getOrders(account: string, options={}) {
return utils.promisify(getOrdersAsync.bind(this))(account, options); return utils.promisify(getOrdersAsync).call(this, account, options);
} }
module.exports = getOrders; module.exports = getOrders;

View File

@@ -0,0 +1,50 @@
/* @flow */
'use strict';
const _ = require('lodash');
const removeUndefined = require('./utils').removeUndefined;
const parseTransaction = require('./transaction');
function parseTransactions(transactions) {
if (_.isEmpty(transactions)) {
return {};
}
if (_.isString(transactions[0])) {
return {transactionHashes: transactions};
}
return {
transactions: _.map(transactions, parseTransaction),
rawTransactions: JSON.stringify(transactions)
};
}
function parseState(state) {
if (_.isEmpty(state)) {
return {};
}
if (_.isString(state[0])) {
return {stateHashes: state};
}
return {rawState: JSON.stringify(state)};
}
function parseLedger(ledger: Object): Object {
return removeUndefined(_.assign({
accepted: ledger.accepted,
closed: ledger.closed,
stateHash: ledger.account_hash,
closeTime: ledger.close_time,
closeTimeResolution: ledger.close_time_resolution,
closeFlags: ledger.close_flags,
ledgerHash: ledger.hash || ledger.ledger_hash,
ledgerVersion: parseInt(ledger.ledger_index || ledger.seqNum, 10),
parentLedgerHash: ledger.parent_hash,
parentCloseTime: ledger.parent_close_time,
totalDrops: ledger.total_coins || ledger.totalCoins,
transactionHash: ledger.transaction_hash
},
parseTransactions(ledger.transactions),
parseState(ledger.accountState)
));
}
module.exports = parseLedger;

View File

@@ -114,7 +114,7 @@ function getPathsAsync(pathfind, callback) {
} }
function getPaths(pathfind: Object) { function getPaths(pathfind: Object) {
return utils.promisify(getPathsAsync.bind(this))(pathfind); return utils.promisify(getPathsAsync).call(this, pathfind);
} }
module.exports = getPaths; module.exports = getPaths;

View File

@@ -38,7 +38,7 @@ function getSettingsAsync(account, options, callback) {
} }
function getSettings(account: string, options={}) { function getSettings(account: string, options={}) {
return utils.promisify(getSettingsAsync.bind(this))(account, options); return utils.promisify(getSettingsAsync).call(this, account, options);
} }
module.exports = getSettings; module.exports = getSettings;

View File

@@ -87,7 +87,7 @@ function getTransactionAsync(identifier: string, options: TransactionOptions,
function getTransaction(identifier: string, function getTransaction(identifier: string,
options: TransactionOptions={} options: TransactionOptions={}
): Promise<GetTransactionResponse> { ): Promise<GetTransactionResponse> {
return utils.promisify(getTransactionAsync.bind(this))(identifier, options); return utils.promisify(getTransactionAsync).call(this, identifier, options);
} }
module.exports = getTransaction; module.exports = getTransaction;

View File

@@ -104,7 +104,7 @@ function getTransactionsAsync(account, options, callback) {
const defaults = {maxLedgerVersion: this.remote.getLedgerSequence()}; const defaults = {maxLedgerVersion: this.remote.getLedgerSequence()};
if (options.start) { if (options.start) {
getTransaction.bind(this)(options.start).then(tx => { getTransaction.call(this, options.start).then(tx => {
const ledgerVersion = tx.outcome.ledgerVersion; const ledgerVersion = tx.outcome.ledgerVersion;
const bound = options.earliestFirst ? const bound = options.earliestFirst ?
{minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion}; {minLedgerVersion: ledgerVersion} : {maxLedgerVersion: ledgerVersion};
@@ -118,7 +118,7 @@ function getTransactionsAsync(account, options, callback) {
} }
function getTransactions(account: string, options={}) { function getTransactions(account: string, options={}) {
return utils.promisify(getTransactionsAsync.bind(this))(account, options); return utils.promisify(getTransactionsAsync).call(this, account, options);
} }
module.exports = getTransactions; module.exports = getTransactions;

View File

@@ -10,7 +10,8 @@ function currencyFilter(currency, trustline) {
} }
function getAccountLines(remote, address, ledgerVersion, options, marker, limit, function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
callback) { callback
) {
const requestOptions = { const requestOptions = {
account: address, account: address,
ledger: ledgerVersion, ledger: ledgerVersion,
@@ -31,7 +32,8 @@ function getAccountLines(remote, address, ledgerVersion, options, marker, limit,
function getTrustlinesAsync(account: string, options: {currency: string, function getTrustlinesAsync(account: string, options: {currency: string,
counterparty: string, limit: number, ledgerVersion: number}, counterparty: string, limit: number, ledgerVersion: number},
callback: () => void): void { callback: () => void
): void {
validate.address(account); validate.address(account);
validate.getTrustlinesOptions(options); validate.getTrustlinesOptions(options);
@@ -43,7 +45,7 @@ function getTrustlinesAsync(account: string, options: {currency: string,
} }
function getTrustlines(account: string, options={}) { function getTrustlines(account: string, options={}) {
return utils.promisify(getTrustlinesAsync.bind(this))(account, options); return utils.promisify(getTrustlinesAsync).call(this, account, options);
} }
module.exports = getTrustlines; module.exports = getTrustlines;

View File

@@ -7,7 +7,7 @@ function convertLedgerHeader(header) {
return { return {
accepted: header.accepted, accepted: header.accepted,
closed: header.closed, closed: header.closed,
account_hash: header.accountHash, account_hash: header.stateHash,
close_time: header.closeTime, close_time: header.closeTime,
close_time_resolution: header.closeTimeResolution, close_time_resolution: header.closeTimeResolution,
close_flags: header.closeFlags, close_flags: header.closeFlags,
@@ -28,25 +28,47 @@ function hashLedgerHeader(ledgerHeader) {
return common.core.Ledger.calculateLedgerHash(header); return common.core.Ledger.calculateLedgerHash(header);
} }
function computeLedgerHash(ledgerHeader: Object, transactions: Array<Object> function computeTransactionHash(ledger) {
): string { if (ledger.rawTransactions === undefined) {
if (transactions) { return ledger.transactionHash;
}
const transactions = JSON.parse(ledger.rawTransactions);
const txs = _.map(transactions, tx => { const txs = _.map(transactions, tx => {
const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {}); const mergeTx = _.assign({}, _.omit(tx, 'tx'), tx.tx || {});
const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'), const renameMeta = _.assign({}, _.omit(mergeTx, 'meta'),
tx.meta ? {metaData: tx.meta} : {}); tx.meta ? {metaData: tx.meta} : {});
return renameMeta; return renameMeta;
}); });
const ledger = common.core.Ledger.from_json({transactions: txs}); const ledgerObject = common.core.Ledger.from_json({transactions: txs});
const transactionHash = ledger.calc_tx_hash().to_hex(); const transactionHash = ledgerObject.calc_tx_hash().to_hex();
if (ledgerHeader.transaction_hash !== undefined if (ledger.transactionHash !== undefined
&& ledgerHeader.transaction_hash !== transactionHash) { && ledger.transactionHash !== transactionHash) {
throw new common.errors.ValidationError('transaction_hash in header' throw new common.errors.ValidationError('transactionHash in header'
+ ' does not match computed hash of transactions'); + ' does not match computed hash of transactions');
} }
return hashLedgerHeader(_.assign({}, ledgerHeader, {transactionHash})); return transactionHash;
} }
return hashLedgerHeader(ledgerHeader);
function computeStateHash(ledger) {
if (ledger.rawState === undefined) {
return ledger.stateHash;
}
const state = JSON.parse(ledger.rawState);
const ledgerObject = common.core.Ledger.from_json({accountState: state});
const stateHash = ledgerObject.calc_account_hash().to_hex();
if (ledger.stateHash !== undefined && ledger.stateHash !== stateHash) {
throw new common.errors.ValidationError('stateHash in header'
+ ' does not match computed hash of state');
}
return stateHash;
}
function computeLedgerHash(ledger: Object): string {
const hashes = {
transactionHash: computeTransactionHash(ledger),
stateHash: computeStateHash(ledger)
};
return hashLedgerHeader(_.assign({}, ledger, hashes));
} }
module.exports = computeLedgerHash; module.exports = computeLedgerHash;

View File

@@ -34,6 +34,7 @@ function checkResult(expected, schemaName, response) {
if (schemaName) { if (schemaName) {
schemaValidator.schemaValidate(schemaName, response); schemaValidator.schemaValidate(schemaName, response);
} }
return response;
} }
describe('RippleAPI', function() { describe('RippleAPI', function() {
@@ -547,9 +548,27 @@ describe('RippleAPI', function() {
assert.strictEqual(this.api.getLedgerVersion(), 8819951); assert.strictEqual(this.api.getLedgerVersion(), 8819951);
}); });
it('getLedgerHeader', function() { it('getLedger', function() {
return this.api.getLedgerHeader().then( return this.api.getLedger().then(
_.partial(checkResult, responses.getLedgerHeader, 'getLedgerHeader')); _.partial(checkResult, responses.getLedger.header, 'getLedger'));
});
it('getLedger - full, then computeLedgerHash', function() {
const request = {
includeTransactions: true,
includeState: true,
includeAllData: true,
ledgerVersion: 38129
};
return this.api.getLedger(request).then(
_.partial(checkResult, responses.getLedger.full, 'getLedger'))
.then(response => {
const ledger = _.assign({}, response,
{parentCloseTime: response.closeTime});
const hash = this.api.computeLedgerHash(ledger);
assert.strictEqual(hash,
'E6DB7365949BF9814D76BCC730B01818EB9136A89DB224F3F9F5AAE4569D758E');
});
}); });
it('ledger utils - compareTransactions', function() { it('ledger utils - compareTransactions', function() {
@@ -757,9 +776,10 @@ describe('RippleAPI - offline', function() {
it('computeLedgerHash - with transactions', function() { it('computeLedgerHash - with transactions', function() {
const api = new RippleAPI(); const api = new RippleAPI();
const header = _.omit(requests.computeLedgerHash.header, const header = _.omit(requests.computeLedgerHash.header,
'transaction_hash'); 'transactionHash');
const transactions = requests.computeLedgerHash.transactions; header.rawTransactions = JSON.stringify(
const ledgerHash = api.computeLedgerHash(header, transactions); requests.computeLedgerHash.transactions);
const ledgerHash = api.computeLedgerHash(header);
assert.strictEqual(ledgerHash, assert.strictEqual(ledgerHash,
'F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349'); 'F4D865D83EB88C1A1911B9E90641919A1314F36E1B099F8E95FE3B7C77BE3349');
}); });
@@ -767,9 +787,10 @@ describe('RippleAPI - offline', function() {
it('computeLedgerHash - incorrent transaction_hash', function() { it('computeLedgerHash - incorrent transaction_hash', function() {
const api = new RippleAPI(); const api = new RippleAPI();
const header = _.assign({}, requests.computeLedgerHash.header, const header = _.assign({}, requests.computeLedgerHash.header,
{transaction_hash: {transactionHash:
'325EACC5271322539EEEC2D6A5292471EF1B3E72AE7180533EFC3B8F0AD435C9'}); '325EACC5271322539EEEC2D6A5292471EF1B3E72AE7180533EFC3B8F0AD435C9'});
const transactions = requests.computeLedgerHash.transactions; header.rawTransactions = JSON.stringify(
assert.throws(() => api.computeLedgerHash(header, transactions)); requests.computeLedgerHash.transactions);
assert.throws(() => api.computeLedgerHash(header));
}); });
}); });

View File

@@ -1,6 +1,6 @@
{ {
"accepted": true, "accepted": true,
"accountHash": "D9ABF622DA26EEEE48203085D4BC23B0F77DC6F8724AC33D975DA3CA492D2E44", "stateHash": "D9ABF622DA26EEEE48203085D4BC23B0F77DC6F8724AC33D975DA3CA492D2E44",
"closeTime": 492656470, "closeTime": 492656470,
"parentCloseTime": 492656460, "parentCloseTime": 492656460,
"closeFlags": 0, "closeFlags": 0,

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,12 @@
{ {
"accepted": true, "accepted": true,
"closed": true, "closed": true,
"accountHash": "EC028EC32896D537ECCA18D18BEBE6AE99709FEFF9EF72DBD3A7819E918D8B96", "stateHash": "EC028EC32896D537ECCA18D18BEBE6AE99709FEFF9EF72DBD3A7819E918D8B96",
"closeTime": 464908910, "closeTime": 464908910,
"closeTimeResolution": 10, "closeTimeResolution": 10,
"closeFlags": 0, "closeFlags": 0,
"ledgerHash": "0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A0F", "ledgerHash": "0F7ED9F40742D8A513AE86029462B7A6768325583DF8EE21B7EC663019DD6A0F",
"ledgerVersion": "9038214", "ledgerVersion": 9038214,
"parentLedgerHash": "4BB9CBE44C39DC67A1BE849C7467FE1A6D1F73949EA163C38A0121A15E04FFDE", "parentLedgerHash": "4BB9CBE44C39DC67A1BE849C7467FE1A6D1F73949EA163C38A0121A15E04FFDE",
"parentCloseTime": 464908900, "parentCloseTime": 464908900,
"totalDrops": "99999973964317514", "totalDrops": "99999973964317514",

View File

@@ -27,7 +27,10 @@ module.exports = {
}, },
getTransactions: require('./get-transactions.json'), getTransactions: require('./get-transactions.json'),
getTrustlines: require('./get-trustlines.json'), getTrustlines: require('./get-trustlines.json'),
getLedgerHeader: require('./get-ledger-header'), getLedger: {
header: require('./get-ledger'),
full: require('./get-ledger-full')
},
prepareOrderCancellation: require('./prepare-order-cancellation.json'), prepareOrderCancellation: require('./prepare-order-cancellation.json'),
prepareOrder: require('./prepare-order.json'), prepareOrder: require('./prepare-order.json'),
prepareOrderSell: require('./prepare-order-sell.json'), prepareOrderSell: require('./prepare-order-sell.json'),

View File

@@ -8,6 +8,7 @@ const addresses = require('./fixtures/addresses');
const hashes = require('./fixtures/hashes'); const hashes = require('./fixtures/hashes');
const transactionsResponse = require('./fixtures/api/rippled/account-tx'); const transactionsResponse = require('./fixtures/api/rippled/account-tx');
const accountLinesResponse = require('./fixtures/api/rippled/account-lines'); const accountLinesResponse = require('./fixtures/api/rippled/account-lines');
const fullLedger = require('./fixtures/ledger-full-38129.json');
function isUSD(json) { function isUSD(json) {
return json === 'USD' || json === '0000000000000000000000005553440000000000'; return json === 'USD' || json === '0000000000000000000000005553440000000000';
@@ -24,6 +25,27 @@ function createResponse(request, response, overrides={}) {
return JSON.stringify(_.assign({}, response, change)); return JSON.stringify(_.assign({}, response, change));
} }
function createLedgerResponse(request, response) {
const newResponse = JSON.parse(createResponse(request, response));
if (newResponse.result && newResponse.result.ledger) {
if (!request.transactions) {
delete newResponse.result.ledger.transactions;
}
if (!request.accounts) {
delete newResponse.result.ledger.accountState;
}
// the following fields were not in the ledger response in the past
if (newResponse.result.ledger.close_flags === undefined) {
newResponse.result.ledger.close_flags = 0;
}
if (newResponse.result.ledger.parent_close_time === undefined) {
newResponse.result.ledger.parent_close_time =
newResponse.result.ledger.close_time - 10;
}
}
return JSON.stringify(newResponse);
}
module.exports = function(port) { module.exports = function(port) {
const mock = new WebSocketServer({port: port}); const mock = new WebSocketServer({port: port});
_.assign(mock, EventEmitter2.prototype); _.assign(mock, EventEmitter2.prototype);
@@ -119,11 +141,15 @@ module.exports = function(port) {
mock.on('request_ledger', function(request, conn) { mock.on('request_ledger', function(request, conn) {
assert.strictEqual(request.command, 'ledger'); assert.strictEqual(request.command, 'ledger');
if (request.ledger_index === 34) { if (request.ledger_index === 34) {
conn.send(createResponse(request, fixtures.ledgerNotFound)); conn.send(createLedgerResponse(request, fixtures.ledgerNotFound));
} else if (request.ledger_index === 9038215) { } else if (request.ledger_index === 9038215) {
conn.send(createResponse(request, fixtures.ledgerWithoutCloseTime)); conn.send(createLedgerResponse(request, fixtures.ledgerWithoutCloseTime));
} else if (request.ledger_index === 38129) {
const response = _.assign({}, fixtures.ledger,
{result: {ledger: fullLedger}});
conn.send(createLedgerResponse(request, response));
} else { } else {
conn.send(createResponse(request, fixtures.ledger)); conn.send(createLedgerResponse(request, fixtures.ledger));
} }
}); });