Compare commits

...

30 Commits

Author SHA1 Message Date
Chris Clark
bd4e0e01e2 Merge pull request #739 from clark800/develop
Update ripple-binary-codec and ripple-hashes dependencies
2016-11-30 14:59:52 -08:00
Chris Clark
cfcf6e473c Update ripple-binary-codec and ripple-hashes dependencies 2016-11-30 14:49:40 -08:00
Chris Clark
50c6af3158 Merge pull request #734 from clark800/bump-codec
Bump version to 0.17.3 and bump ripple-binary-codec to 0.1.4
2016-09-29 11:24:04 -07:00
Chris Clark
1d4310cd3a Disable flow type checking in CircleCI 2016-09-29 11:19:46 -07:00
Chris Clark
2191596e68 Bump version to 0.17.3 and bump ripple-binary-codec to 0.1.4 2016-09-29 11:19:32 -07:00
Chris Clark
acf8f87a88 Merge pull request #727 from clark800/order-seq
Add orderToReplace option
2016-08-01 14:34:27 -07:00
Chris Clark
cfac146620 Add orderToReplace option 2016-08-01 14:27:08 -07:00
Chris Clark
f3234ad853 Merge pull request #726 from clark800/doc-typos
Fix typos in docs
2016-08-01 14:24:22 -07:00
Chris Clark
b65fee3d85 Merge pull request #725 from shekenahglory/develop
update parseDeliveredAmount for cases where delivered_amount is not p…
2016-08-01 14:21:43 -07:00
Chris Clark
82b294bc7d Update flow 2016-08-01 14:13:00 -07:00
Chris Clark
2a58573823 Fix typos in docs 2016-08-01 11:53:46 -07:00
Matthew Fettig
a96f71b7fd fix missing deliveredAmount data from getLedger requests 2016-07-19 21:29:50 -07:00
Chris Clark
077f4a4c79 Merge pull request #723 from clark800/fix-coverage
Fix code coverage tool
2016-07-08 15:04:38 -07:00
Chris Clark
9a495467fb Disable sauce tests because they usually timeout 2016-07-08 11:45:27 -07:00
Chris Clark
db2e62b219 Fix code coverage tool 2016-07-08 11:28:10 -07:00
Alan Cohen
2fafa493a2 Version 0.17.2 2016-06-24 10:59:04 -07:00
Alan Cohen
7617c3005c Merge pull request #721 from mDuo13/fix_transferrate_docs
[DOC] fix transferRate description
2016-06-22 11:13:14 -07:00
mDuo13
5cdbb71277 [DOC] fix transferRate description 2016-06-16 15:11:08 -07:00
Chris Clark
f9339c36bf Merge pull request #720 from clark800/update-binary-codec
0.17.1
2016-05-11 18:20:29 -07:00
Chris Clark
67dc57e9d0 Disable PhantomJS tests due to issue downloading from bitbucket 2016-05-11 17:49:57 -07:00
Chris Clark
757f3190d1 0.17.1 2016-05-11 17:49:54 -07:00
Chris Clark
0d94a15ee7 0.17.0 2016-05-05 18:35:13 -07:00
Chris Clark
7f1c80da1b Merge pull request #718 from clark800/pseudo
Add support for parsing SetFee and EnableAmendment pseudo-transactions
2016-05-05 16:15:32 -07:00
Chris Clark
f74e11bce0 Add support for parsing SetFee and EnableAmendment pseudo-transactions 2016-05-05 15:37:23 -07:00
Chris Clark
d4c843e8e3 Merge pull request #714 from darkdarkdragon/remove_tej
[FIX] remove check for `tej` class of errors.
2016-04-05 15:15:42 -07:00
Ivan Tivonenko
bae190b282 [FIX] remove check for tej class of errors. 2016-04-05 23:50:41 +03:00
Chris Clark
d2cbd70da8 Merge pull request #712 from darkdarkdragon/reconnect_fix_browser
[FIX] on reconnect wait for server to be synced
2016-03-30 15:50:58 -07:00
Ivan Tivonenko
5da78ce583 [FIX] handle websocket errors in browsers
emit not RippledNotInitializedError if server doesn't have any
completed ledgers on connect
2016-03-31 00:46:00 +03:00
Chris Clark
14bbe3e30b Merge pull request #680 from ripple/sublimator-patch-1
Fix typo in docs
2016-03-29 10:27:34 -07:00
Nicholas Dudfield
e52e2bbc68 Fix IOU Amount precision related typo in docs 2016-03-29 13:51:30 +07:00
40 changed files with 5789 additions and 438 deletions

View File

@@ -5,6 +5,7 @@ machine:
testripple.circleci.com: 127.0.0.1
dependencies:
pre:
- npm -g install npm@latest-2
- wget https://s3-us-west-2.amazonaws.com/ripple-debs/rippled_0.30.1-b11-1.deb
- sudo dpkg -i rippled_0.30.1-b11-1.deb
test:

View File

@@ -211,7 +211,7 @@ A *value* is a quantity of a currency represented as a decimal string. Be carefu
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
## Amount
@@ -430,6 +430,7 @@ expirationTime | date-time string | *Optional* Time after which the offer is no
fillOrKill | boolean | *Optional* Treat the offer as a [Fill or Kill order](http://en.wikipedia.org/wiki/Fill_or_kill). Only attempt to match existing offers in the ledger, and only do so if the entire quantity can be exchanged.
immediateOrCancel | boolean | *Optional* Treat the offer as an [Immediate or Cancel order](http://en.wikipedia.org/wiki/Immediate_or_cancel). If enabled, the offer will never become a ledger node: it only attempts to match existing offers in the ledger.
memos | [memos](#transaction-memos) | *Optional* Array of memos to attach to the transaction.
orderToReplace | [sequence](#account-sequence-number) | *Optional* The [account sequence number](#account-sequence-number) of an order to cancel before the new order is created, effectively replacing the old order.
passive | boolean | *Optional* If enabled, the offer will not consume offers that exactly match it, and instead becomes an Offer node in the ledger. It will still consume offers that cross it.
### Example
@@ -498,7 +499,7 @@ signers | object | *Optional* Settings that determine what sets of accounts can
*signers.* weights[] | object | An association of an address and a weight.
*signers.weights[].* address | [address](#ripple-address) | A Ripple account address
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
transferRate | number,null | *Optional* The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.
transferRate | number,null | *Optional* The fee to charge when users transfer this accounts issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
### Example
@@ -1511,7 +1512,7 @@ options | object | *Optional* Options to determine how the balances will be calc
### Return Value
This method returns a promise that resolves with an array of objects with the following structure:
This method returns a promise that resolves with an object with the following structure:
Name | Type | Description
---- | ---- | -----------
@@ -2684,7 +2685,7 @@ signers | object | *Optional* Settings that determine what sets of accounts can
*signers.* weights[] | object | An association of an address and a weight.
*signers.weights[].* address | [address](#ripple-address) | A Ripple account address
*signers.weights[].* weight | integer | The weight that the signature of this account counts as towards the threshold.
transferRate | number,null | *Optional* The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.
transferRate | number,null | *Optional* The fee to charge when users transfer this accounts issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.
### Example
@@ -3051,7 +3052,7 @@ instructions | object | The instructions for how to execute the transaction afte
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const orderCancellation = {orderSequence: 123};
return api.prepareOrderCancellation(address, sequence)
return api.prepareOrderCancellation(address, orderCancellation)
.then(prepared => {/* ... */});
```

View File

@@ -21,7 +21,7 @@ A *value* is a quantity of a currency represented as a decimal string. Be carefu
**XRP** has 6 significant digits past the decimal point. In other words, XRP cannot be divided into positive values smaller than `0.000001` (1e-6). XRP has a maximum value of `100000000000` (1e11).
**Non-XRP values** have 15 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
**Non-XRP values** have 16 decimal digits of precision, with a maximum value of `9999999999999999e80`. The smallest positive non-XRP value is `1e-81`.
## Amount

View File

@@ -10,7 +10,7 @@ Returns aggregate balances by currency plus a breakdown of assets and obligation
### Return Value
This method returns a promise that resolves with an array of objects with the following structure:
This method returns a promise that resolves with an object with the following structure:
<%- renderSchema('output/get-balance-sheet.json') %>

View File

@@ -23,7 +23,7 @@ All "prepare*" methods have the same return type.
```javascript
const address = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
const orderCancellation = {orderSequence: 123};
return api.prepareOrderCancellation(address, sequence)
return api.prepareOrderCancellation(address, orderCancellation)
.then(prepared => {/* ... */});
```

4332
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.16.10",
"version": "0.17.4",
"license": "ISC",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [
@@ -15,7 +15,8 @@
"test": "test"
},
"dependencies": {
"ajv": "^1.4.8",
"ajv": "^4.0.5",
"ajv-i18n": "^1.2.0",
"babel-polyfill": "^6.3.14",
"babel-runtime": "^6.3.19",
"bignumber.js": "^2.0.3",
@@ -23,8 +24,8 @@
"jayson": "^1.2.2",
"lodash": "^3.1.0",
"ripple-address-codec": "^2.0.1",
"ripple-binary-codec": "^0.1.2",
"ripple-hashes": "^0.1.0",
"ripple-binary-codec": "^0.1.5",
"ripple-hashes": "^0.2.0",
"ripple-keypairs": "^0.10.0",
"ripple-lib-transactionparser": "^0.6.0",
"ws": "^1.0.1"
@@ -33,31 +34,29 @@
"assert-diff": "^1.0.1",
"babel-cli": "^6.4.0",
"babel-core": "^6.4.0",
"babel-eslint": "^4.1.8",
"babel-eslint": "^6.0.4",
"babel-loader": "^6.2.1",
"babel-plugin-syntax-flow": "^6.3.13",
"babel-plugin-transform-flow-strip-types": "^6.4.0",
"babel-preset-es2015": "^6.3.13",
"babel-preset-stage-1": "^6.3.13",
"babel-register": "^6.3.13",
"coveralls": "^2.10.0",
"coveralls": "^2.11.9",
"doctoc": "^0.15.0",
"ejs": "^2.3.4",
"eslint": "^2.1.0",
"eslint": "^2.9.0",
"eventemitter2": "^0.4.14",
"flow-bin": "^0.14",
"gulp": "^3.8.10",
"gulp-bump": "^0.1.13",
"gulp-rename": "^1.2.0",
"gulp-uglify": "^1.1.0",
"http-server": "^0.8.5",
"isparta": "^4.0.0",
"istanbul": "^1.1.0-alpha.1",
"json-loader": "^0.5.2",
"json-schema-to-markdown-table": "^0.4.0",
"mocha": "^2.1.0",
"mocha-junit-reporter": "^1.9.1",
"mocha-phantomjs": "^4.0.1",
"mocha-in-sauce": "^0.0.1",
"mocha-junit-reporter": "^1.9.1",
"null-loader": "^0.1.1",
"webpack": "^1.5.3",
"yargs": "^1.3.1"
@@ -72,7 +71,7 @@
"watch": "babel -w -D --optional runtime -d dist/npm/ src/",
"compile-with-source-maps": "babel -D --optional runtime -s -t -d dist/npm/ src/",
"prepublish": "npm run clean && npm run compile",
"test": "babel-node node_modules/isparta/lib/cli cover ./node_modules/mocha/bin/_mocha",
"test": "babel-node ./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha",
"coveralls": "cat ./coverage/lcov.info | coveralls",
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/es6/eslintrc'; echo 'parser: babel-eslint' >> eslintrc; fi; eslint -c eslintrc src/",
"perf": "./scripts/perf_test.sh",

View File

@@ -35,21 +35,21 @@ unittest() {
ln -nfs ../../dist/npm test-compiled/node_modules/ripple-api
mocha --opts test-compiled/mocha.opts test-compiled
# compile tests for browser testing
gulp build-min build-tests
node --harmony test-compiled/mocked-server.js > /dev/null &
#compile tests for browser testing
#gulp build-min build-tests
#node --harmony test-compiled/mocked-server.js > /dev/null &
echo "Running tests in PhantomJS"
mocha-phantomjs test/localrunner.html
echo "Running tests using minified version in PhantomJS"
mocha-phantomjs test/localrunnermin.html
#echo "Running tests in PhantomJS"
#mocha-phantomjs test/localrunner.html
#echo "Running tests using minified version in PhantomJS"
#mocha-phantomjs test/localrunnermin.html
echo "Running tests in SauceLabs"
http-server &
npm run sauce
#echo "Running tests in SauceLabs"
#http-server &
#npm run sauce
pkill -f mocked-server.js
pkill -f http-server
#pkill -f mocked-server.js
#pkill -f http-server
rm -rf test-compiled
}
@@ -58,9 +58,9 @@ integrationtest() {
mocha test/integration/http-integration-test.js
# run integration tests in PhantomJS
gulp build-tests build-min
echo "Running integragtion tests in PhantomJS"
mocha-phantomjs test/localintegrationrunner.html
#gulp build-tests build-min
#echo "Running integragtion tests in PhantomJS"
#mocha-phantomjs test/localintegrationrunner.html
}
doctest() {
@@ -76,7 +76,6 @@ oneNode() {
checkEOL
doctest
lint
typecheck
unittest
integrationtest
}
@@ -84,7 +83,7 @@ oneNode() {
twoNodes() {
case "$NODE_INDEX" in
0) doctest; lint; integrationtest;;
1) checkEOL; typecheck; unittest;;
1) checkEOL; unittest;;
*) echo "ERROR: invalid usage"; exit 2;;
esac
}
@@ -92,7 +91,7 @@ twoNodes() {
threeNodes() {
case "$NODE_INDEX" in
0) doctest; lint; integrationtest;;
1) checkEOL; typecheck;;
1) checkEOL;;
2) unittest;;
*) echo "ERROR: invalid usage"; exit 2;;
esac

View File

@@ -40,6 +40,10 @@ function main() {
version: '43'});
sauce.browser({browserName: 'safari', platform: 'OS X 10.11',
version: '9'});
sauce.browser({browserName: 'safari', platform: 'OS X 10.10',
version: '8'});
sauce.browser({browserName: 'safari', platform: 'OS X 10.9',
version: '7'});
sauce.browser({browserName: 'chrome', platform: 'OS X 10.11',
version: '47'});
sauce.browser({browserName: 'chrome', platform: 'Linux',

View File

@@ -6,7 +6,8 @@ const WebSocket = require('ws');
const parseURL = require('url').parse;
const RangeSet = require('./rangeset').RangeSet;
const {RippledError, DisconnectedError, NotConnectedError,
TimeoutError, ResponseFormatError, ConnectionError} = require('./errors');
TimeoutError, ResponseFormatError, ConnectionError,
RippledNotInitializedError} = require('./errors');
function isStreamMessageType(type) {
return type === 'ledgerClosed' ||
@@ -39,6 +40,8 @@ class Connection extends EventEmitter {
this._nextRequestID = 1;
this._retry = 0;
this._retryTimer = null;
this._onOpenErrorBound = null;
this._onUnexpectedCloseBound = null;
}
_updateLedgerVersions(data) {
@@ -104,6 +107,8 @@ class Connection extends EventEmitter {
this._ws.removeListener('error', this._onOpenErrorBound);
this._onOpenErrorBound = null;
}
// just in case
this._ws.removeAllListeners('open');
this._ws = null;
this._isReady = false;
if (beforeOpen) {
@@ -136,6 +141,7 @@ class Connection extends EventEmitter {
this._retry += 1;
const retryTimeout = this._calculateTimeout(this._retry);
this._retryTimer = setTimeout(() => {
this.emit('reconnecting', this._retry);
this.connect().catch(this._retryConnect.bind(this));
}, retryTimeout);
}
@@ -146,8 +152,13 @@ class Connection extends EventEmitter {
}
_onOpen() {
this._ws.removeListener('error', this._onOpenErrorBound);
this._onOpenErrorBound = null;
if (!this._ws) {
return Promise.reject(new DisconnectedError());
}
if (this._onOpenErrorBound) {
this._ws.removeListener('error', this._onOpenErrorBound);
this._onOpenErrorBound = null;
}
const request = {
command: 'subscribe',
@@ -157,20 +168,22 @@ class Connection extends EventEmitter {
if (_.isEmpty(data) || !data.ledger_index) {
// rippled instance doesn't have validated ledgers
return this._disconnect(false).then(() => {
throw new NotConnectedError('Rippled not initialized');
throw new RippledNotInitializedError('Rippled not initialized');
});
}
this._updateLedgerVersions(data);
this._ws.removeListener('close', this._onUnexpectedCloseBound);
this._onUnexpectedCloseBound =
this._onUnexpectedClose.bind(this, false, null, null);
this._ws.once('close', this._onUnexpectedCloseBound);
this._rebindOnUnxpectedClose();
this._retry = 0;
this._ws.on('error', error =>
this.emit('error', 'websocket', error.message, error));
this._ws.on('error', error => {
if (process.browser && error && error.type === 'error') {
// we are in browser, ignore error - `close` event will be fired
// after error
return;
}
this.emit('error', 'websocket', error.message, error);
});
this._isReady = true;
this.emit('connected');
@@ -179,8 +192,25 @@ class Connection extends EventEmitter {
});
}
_rebindOnUnxpectedClose() {
if (this._onUnexpectedCloseBound) {
this._ws.removeListener('close', this._onUnexpectedCloseBound);
}
this._onUnexpectedCloseBound =
this._onUnexpectedClose.bind(this, false, null, null);
this._ws.once('close', this._onUnexpectedCloseBound);
}
_unbindOnUnxpectedClose() {
if (this._onUnexpectedCloseBound) {
this._ws.removeListener('close', this._onUnexpectedCloseBound);
}
this._onUnexpectedCloseBound = null;
}
_onOpenError(reject, error) {
this._onOpenErrorBound = null;
this._unbindOnUnxpectedClose();
reject(new NotConnectedError(error && error.message));
}
@@ -277,7 +307,10 @@ class Connection extends EventEmitter {
} else if (this._state === WebSocket.CLOSING) {
this._ws.once('close', resolve);
} else {
this._ws.removeListener('close', this._onUnexpectedCloseBound);
if (this._onUnexpectedCloseBound) {
this._ws.removeListener('close', this._onUnexpectedCloseBound);
this._onUnexpectedCloseBound = null;
}
this._ws.once('close', code => {
this._ws = null;
this._isReady = false;

View File

@@ -1,4 +1,4 @@
'use strict';
'use strict'; // eslint-disable-line
const util = require('util');
const browserHacks = require('./browser-hacks');
@@ -53,6 +53,8 @@ class NotConnectedError extends ConnectionError {}
class DisconnectedError extends ConnectionError {}
class RippledNotInitializedError extends ConnectionError {}
class TimeoutError extends ConnectionError {}
class ResponseFormatError extends ConnectionError {}
@@ -85,6 +87,7 @@ module.exports = {
RippledError,
NotConnectedError,
DisconnectedError,
RippledNotInitializedError,
TimeoutError,
ResponseFormatError,
ValidationError,

View File

@@ -55,7 +55,7 @@
"description": " The domain that owns this account, as a hexadecimal string representing the ASCII for the domain in lowercase."
},
"transferRate": {
"description": " The fee to charge when users transfer this accounts issuances, represented as billionths of a unit. Use `null` to set no fee.",
"description": " The fee to charge when users transfer this accounts issuances, as the decimal amount that must be sent to deliver 1 unit. Has precision up to 9 digits beyond the decimal point. Use `null` to set no fee.",
"oneOf": [
{"type": "null"},
{"type": "number", "minimum": 1, "maximum": 4.294967295}

View File

@@ -34,6 +34,10 @@
"format": "date-time",
"description": "Time after which the offer is no longer active, as an [ISO 8601 date-time](https://en.wikipedia.org/wiki/ISO_8601)."
},
"orderToReplace": {
"$ref": "sequence",
"description": "The [account sequence number](#account-sequence-number) of an order to cancel before the new order is created, effectively replacing the old order."
},
"memos": {"$ref": "memos"}
},
"required": ["direction", "quantity", "totalPrice"],

View File

@@ -0,0 +1,9 @@
'use strict'; // eslint-disable-line strict
function parseAmendment(tx: Object) {
return {
amendment: tx.Amendment
};
}
module.exports = parseAmendment;

View File

@@ -0,0 +1,15 @@
'use strict'; // eslint-disable-line strict
const BigNumber = require('bignumber.js');
const {dropsToXrp} = require('./utils');
function parseFeeUpdate(tx: Object) {
const baseFeeDrops = (new BigNumber(tx.BaseFee, 16)).toString();
return {
baseFeeXRP: dropsToXrp(baseFeeDrops),
referenceFeeUnits: tx.ReferenceFeeUnits,
reserveBaseXRP: dropsToXrp(tx.ReserveBase),
reserveIncrementXRP: dropsToXrp(tx.ReserveIncrement)
};
}
module.exports = parseFeeUpdate;

View File

@@ -1,13 +1,15 @@
/* @flow */
'use strict';
'use strict'; // eslint-disable-line
const _ = require('lodash');
const {removeUndefined, rippleTimeToISO8601} = require('./utils');
const parseTransaction = require('./transaction');
import type {GetLedger} from '../types.js';
function parseTransactionWrapper(ledgerVersion, tx) {
const transaction = _.assign({}, _.omit(tx, 'metaData'),
{meta: tx.metaData});
const transaction = _.assign({}, _.omit(tx, 'metaData'), {
meta: tx.metaData,
ledger_index: ledgerVersion
});
const result = parseTransaction(transaction);
if (!result.outcome.ledgerVersion) {
result.outcome.ledgerVersion = ledgerVersion;

View File

@@ -1,5 +1,5 @@
/* @flow */
'use strict';
'use strict'; // eslint-disable-line strict
const assert = require('assert');
const utils = require('./utils');
const parsePayment = require('./payment');
@@ -11,6 +11,8 @@ const parseSuspendedPaymentCreation = require('./suspended-payment-creation');
const parseSuspendedPaymentExecution = require('./suspended-payment-execution');
const parseSuspendedPaymentCancellation =
require('./suspended-payment-cancellation');
const parseFeeUpdate = require('./fee-update');
const parseAmendment = require('./amendment');
function parseTransactionType(type) {
const mapping = {
@@ -23,7 +25,9 @@ function parseTransactionType(type) {
SuspendedPaymentCreate: 'suspendedPaymentCreation',
SuspendedPaymentFinish: 'suspendedPaymentExecution',
SuspendedPaymentCancel: 'suspendedPaymentCancellation',
SignerListSet: 'settings'
SignerListSet: 'settings',
SetFee: 'feeUpdate', // pseudo-transaction
EnableAmendment: 'amendment' // pseudo-transaction
};
return mapping[type] || null;
}
@@ -38,7 +42,9 @@ function parseTransaction(tx: Object): Object {
'settings': parseSettings,
'suspendedPaymentCreation': parseSuspendedPaymentCreation,
'suspendedPaymentExecution': parseSuspendedPaymentExecution,
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation
'suspendedPaymentCancellation': parseSuspendedPaymentCancellation,
'feeUpdate': parseFeeUpdate,
'amendment': parseAmendment
};
const parser = mapping[type];
assert(parser !== undefined, 'Unrecognized transaction type');

View File

@@ -1,5 +1,5 @@
/* @flow */
'use strict';
'use strict'; // eslint-disable-line
const _ = require('lodash');
const transactionParser = require('ripple-lib-transactionparser');
const utils = require('../utils');
@@ -56,19 +56,43 @@ function isPartialPayment(tx) {
}
function parseDeliveredAmount(tx: Object): Amount | void {
let deliveredAmount;
// TODO: Workaround for existing rippled bug where delivered_amount may not be
// provided for account_tx
if (tx.TransactionType === 'Payment') {
if (tx.meta.delivered_amount) {
deliveredAmount = parseAmount(tx.meta.delivered_amount);
} else if (tx.Amount && !isPartialPayment(tx)) {
deliveredAmount = parseAmount(tx.Amount);
}
if (tx.TransactionType !== 'Payment' ||
tx.meta.TransactionResult !== 'tesSUCCESS') {
return undefined;
}
return deliveredAmount;
if (tx.meta.delivered_amount &&
tx.meta.delivered_amount === 'unavailable') {
return undefined;
}
// parsable delivered_amount
if (tx.meta.delivered_amount) {
return parseAmount(tx.meta.delivered_amount);
}
// DeliveredAmount only present on partial payments
if (tx.meta.DeliveredAmount) {
return parseAmount(tx.meta.DeliveredAmount);
}
// no partial payment flag, use tx.Amount
if (tx.Amount && !isPartialPayment(tx)) {
return parseAmount(tx.Amount);
}
// DeliveredAmount field was introduced at
// ledger 4594095 - after that point its absence
// on a tx flagged as partial payment indicates
// the full amount was transferred. The amount
// transferred with a partial payment before
// that date must be derived from metadata.
if (tx.Amount && tx.ledger_index > 4594094) {
return parseAmount(tx.Amount);
}
return undefined;
}
function parseOutcome(tx: Object): ?Object {

View File

@@ -1,5 +1,5 @@
/* @flow */
'use strict';
'use strict'; // eslint-disable-line strict
const _ = require('lodash');
const utils = require('./utils');
const parseTransaction = require('./parse/transaction');
@@ -13,15 +13,18 @@ function attachTransactionDate(connection: Connection, tx: Object
return Promise.resolve(tx);
}
if (!tx.ledger_index) {
const ledgerVersion = tx.ledger_index || tx.LedgerSequence;
if (!ledgerVersion) {
return new Promise(() => {
throw new errors.NotFoundError('ledger_index not found in tx');
throw new errors.NotFoundError(
'ledger_index and LedgerSequence not found in tx');
});
}
const request = {
command: 'ledger',
ledger_index: tx.ledger_index
ledger_index: ledgerVersion
};
return connection.request(request).then(data => {

View File

@@ -1,5 +1,5 @@
/* @flow */
'use strict';
'use strict'; // eslint-disable-line
const _ = require('lodash');
const utils = require('./utils');
const offerFlags = utils.common.txFlags.OfferCreate;
@@ -35,6 +35,9 @@ function createOrderTransaction(account: string, order: Order): Object {
if (order.expirationTime !== undefined) {
txJSON.Expiration = iso8601ToRippleTime(order.expirationTime);
}
if (order.orderToReplace !== undefined) {
txJSON.OfferSequence = order.orderToReplace;
}
if (order.memos !== undefined) {
txJSON.Memos = _.map(order.memos, utils.convertMemo);
}

View File

@@ -1,5 +1,5 @@
/* @flow */
'use strict';
'use strict'; // eslint-disable-line
const _ = require('lodash');
const utils = require('./utils');
const {validate} = utils.common;
@@ -12,7 +12,7 @@ function isImmediateRejection(engineResult: string): boolean {
// if the required fee changes (this does not occur at the time of
// this writing, but it could change in the future)
// all other error classes can potentially result in transcation validation
return _.startsWith(engineResult, 'tem') || _.startsWith(engineResult, 'tej');
return _.startsWith(engineResult, 'tem');
}
function formatSubmitResponse(response) {

View File

@@ -1,5 +1,5 @@
/* eslint-disable max-nested-callbacks */
'use strict'; // eslint-disable-line
'use strict'; // eslint-disable-line
const _ = require('lodash');
const assert = require('assert-diff');
const setupAPI = require('./setup-api');
@@ -708,6 +708,21 @@ describe('RippleAPI', function() {
});
});
it('getTransaction - amendment', function() {
const hash =
'A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F';
return this.api.getTransaction(hash).then(result => {
assert.deepEqual(result, responses.getTransaction.amendment);
});
});
it('getTransaction - feeUpdate', function() {
const hash =
'C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF';
return this.api.getTransaction(hash).then(result => {
assert.deepEqual(result, responses.getTransaction.feeUpdate);
});
});
});
it('getTransactions', function() {
@@ -1156,6 +1171,28 @@ describe('RippleAPI', function() {
_.partial(checkResult, responses.getLedger.withSettingsTx, 'getLedger'));
});
it('getLedger - with partial payment', function() {
const request = {
includeTransactions: true,
includeAllData: true,
ledgerVersion: 100000
};
return this.api.getLedger(request).then(
_.partial(checkResult, responses.getLedger.withPartial, 'getLedger'));
});
it('getLedger - pre 2014 with partial payment', function() {
const request = {
includeTransactions: true,
includeAllData: true,
ledgerVersion: 100001
};
return this.api.getLedger(request).then(
_.partial(checkResult,
responses.getLedger.pre2014withPartial,
'getLedger'));
});
it('getLedger - full, then computeLedgerHash', function() {
const request = {
includeTransactions: true,

View File

@@ -194,49 +194,81 @@ describe('Connection', function() {
}, 1);
});
it('reconnect on several unexpected close', function(done) {
if (process.browser) {
// can't be tested in browser this way, so skipping
done();
return;
}
this.timeout(7000);
const self = this;
function breakConnection() {
setTimeout(() => {
self.mockRippled.close();
setTimeout(() => {
self.mockRippled = setupAPI.createMockRippled(self._mockedServerPort);
}, 1500);
}, 21);
}
let connectsCount = 0;
let disconnectsCount = 0;
let code = 0;
this.api.connection.on('disconnected', _code => {
code = _code;
disconnectsCount += 1;
describe('reconnection test', function() {
beforeEach(function() {
this.api.connection.__workingUrl = this.api.connection._url;
this.api.connection.__doReturnBad = function() {
this._url = this.__badUrl;
const self = this;
function onReconnect(num) {
if (num >= 2) {
self._url = self.__workingUrl;
self.removeListener('reconnecting', onReconnect);
}
}
this.on('reconnecting', onReconnect);
};
});
this.api.connection.on('connected', () => {
connectsCount += 1;
if (connectsCount < 3) {
breakConnection();
}
if (connectsCount === 3) {
if (disconnectsCount !== 3) {
done(new Error('disconnectsCount must be equal to 3 (got ' +
disconnectsCount + ' instead)'));
} else if (code !== 1006) {
done(new Error('disconnect must send code 1006 (got ' + code +
' instead)'));
} else {
afterEach(function() {
});
it('reconnect on several unexpected close', function(done) {
if (process.browser) {
const phantomTest = /PhantomJS/;
if (phantomTest.test(navigator.userAgent)) {
// inside PhantomJS this one just hangs, so skip as not very relevant
done();
return;
}
}
});
this.timeout(70001);
const self = this;
self.api.connection.__badUrl = 'ws://testripple.circleci.com:129';
function breakConnection() {
self.api.connection.__doReturnBad();
self.api.connection._send(JSON.stringify({
command: 'test_command',
data: {disconnectIn: 10}
}));
}
breakConnection();
let connectsCount = 0;
let disconnectsCount = 0;
let reconnectsCount = 0;
let code = 0;
this.api.connection.on('reconnecting', () => {
reconnectsCount += 1;
});
this.api.connection.on('disconnected', _code => {
code = _code;
disconnectsCount += 1;
});
const num = 3;
this.api.connection.on('connected', () => {
connectsCount += 1;
if (connectsCount < num) {
breakConnection();
}
if (connectsCount === num) {
if (disconnectsCount !== num) {
done(new Error('disconnectsCount must be equal to ' + num +
'(got ' + disconnectsCount + ' instead)'));
} else if (reconnectsCount !== num * 2) {
done(new Error('reconnectsCount must be equal to ' + num * 2 +
' (got ' + reconnectsCount + ' instead)'));
} else if (code !== 1006) {
done(new Error('disconnect must send code 1006 (got ' + code +
' instead)'));
} else {
done();
}
}
});
breakConnection();
});
});
it('should emit disconnected event with code 1000 (CLOSE_NORMAL)',
@@ -252,16 +284,17 @@ describe('Connection', function() {
it('should emit disconnected event with code 1006 (CLOSE_ABNORMAL)',
function(done
) {
if (process.browser) {
// can't be tested in browser this way, so skipping
done();
return;
}
this.api.once('error', error => {
done(new Error('should not throw error, got ' + String(error)));
});
this.api.once('disconnected', code => {
assert.strictEqual(code, 1006);
done();
});
this.mockRippled.close();
this.api.connection._send(JSON.stringify({
command: 'test_command',
data: {disconnectIn: 10}
}));
});
it('should emit connected event on after reconnect', function(done) {
@@ -380,12 +413,9 @@ describe('Connection', function() {
this.api.connection._ws.emit('message', JSON.stringify(message));
});
it('should throw NotConnectedError if server does not have validated ledgers',
it('should throw RippledNotInitializedError if server does not have ' +
'validated ledgers',
function() {
if (process.browser) {
// do not work in browser now, skipping
return false;
}
this.timeout(3000);
this.api.connection._send(JSON.stringify({
@@ -397,18 +427,13 @@ describe('Connection', function() {
return api.connect().then(() => {
assert(false, 'Must have thrown!');
}, error => {
assert(error instanceof this.api.errors.NotConnectedError,
'Must throw NotConnectedError, got instead ' + String(error));
assert(error instanceof this.api.errors.RippledNotInitializedError,
'Must throw RippledNotInitializedError, got instead ' + String(error));
});
});
it('should try to reconnect on empty subscribe response on reconnect',
function(done) {
if (process.browser) {
// do not work in browser now, skipping
done();
return;
}
this.timeout(23000);
this.api.on('error', error => {

View File

@@ -10,6 +10,7 @@
"value": "2"
},
"immediateOrCancel": true,
"orderToReplace": 12345,
"memos": [
{
"type": "test",

View File

@@ -0,0 +1,79 @@
{
"stateHash": "334EE5F2209538C3099E133D25725E5BFEB40A198EA7028E6317F13E95D533DF",
"closeTime": "2016-07-07T16:53:51.000Z",
"closeTimeResolution": 10,
"closeFlags": 0,
"ledgerHash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"ledgerVersion": 12345,
"parentLedgerHash": "4F636662B714CD9CCE965E9C23BB2E1058A2DF496F5A2416299317AE03F1CD35",
"parentCloseTime": "2016-07-07T16:53:50.000Z",
"totalDrops": "99997302532397566",
"transactionHash": "C72A2BDCB471F3AEEB917ABC6019407CAE6DA4B858903A8AB2335A0EB077125D",
"transactions": [
{
"type": "payment",
"address": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"sequence": 23295,
"id": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"specification": {
"source": {
"address": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"maxAmount": {
"currency": "USD",
"value": "10",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"destination": {
"address": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"amount": {
"currency": "USD",
"value": "10",
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
}
},
"allowPartialPayment": true
},
"outcome": {
"result": "tesSUCCESS",
"fee": "0.01",
"balanceChanges": {
"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX": [
{
"currency": "XRP",
"value": "-0.01"
},
{
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"currency": "USD",
"value": "-10"
}
],
"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B": [
{
"counterparty": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"currency": "USD",
"value": "-9.980039920159681"
},
{
"counterparty": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"currency": "USD",
"value": "10"
}
],
"rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4": [
{
"counterparty": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"currency": "USD",
"value": "9.980039920159681"
}
]
},
"orderbookChanges": {},
"ledgerVersion": 12345,
"indexInLedger": 1
}
}
],
"rawTransactions": "[{\"Account\":\"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX\",\"Amount\":{\"currency\":\"USD\",\"issuer\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\",\"value\":\"10\"},\"Destination\":\"rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4\",\"Fee\":\"10000\",\"Flags\":131072,\"Sequence\":23295,\"SigningPubKey\":\"02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53\",\"TransactionType\":\"Payment\",\"TxnSignature\":\"3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D\",\"hash\":\"A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A\",\"metaData\":{\"AffectedNodes\":[{\"ModifiedNode\":{\"FinalFields\":{\"Account\":\"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX\",\"Balance\":\"1930599790\",\"Flags\":0,\"OwnerCount\":2,\"Sequence\":23296},\"LedgerEntryType\":\"AccountRoot\",\"LedgerIndex\":\"267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD\",\"PreviousFields\":{\"Balance\":\"1930609790\",\"Sequence\":23295},\"PreviousTxnID\":\"0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD\",\"PreviousTxnLgrSeq\":22419806}},{\"ModifiedNode\":{\"FinalFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-9.980959751659681\"},\"Flags\":2228224,\"HighLimit\":{\"currency\":\"USD\",\"issuer\":\"rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4\",\"value\":\"1000000\"},\"HighNode\":\"0000000000000000\",\"LowLimit\":{\"currency\":\"USD\",\"issuer\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\",\"value\":\"0\"},\"LowNode\":\"0000000000000423\"},\"LedgerEntryType\":\"RippleState\",\"LedgerIndex\":\"C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5\",\"PreviousFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-0.0009198315\"}},\"PreviousTxnID\":\"2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869\",\"PreviousTxnLgrSeq\":22420532}},{\"ModifiedNode\":{\"FinalFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-276666.975959\"},\"Flags\":131072,\"HighLimit\":{\"currency\":\"USD\",\"issuer\":\"rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX\",\"value\":\"1000000\"},\"HighNode\":\"0000000000000000\",\"LowLimit\":{\"currency\":\"USD\",\"issuer\":\"rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B\",\"value\":\"0\"},\"LowNode\":\"00000000000002D7\"},\"LedgerEntryType\":\"RippleState\",\"LedgerIndex\":\"FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615\",\"PreviousFields\":{\"Balance\":{\"currency\":\"USD\",\"issuer\":\"rrrrrrrrrrrrrrrrrrrrBZbvji\",\"value\":\"-276676.975959\"}},\"PreviousTxnID\":\"BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B\",\"PreviousTxnLgrSeq\":22419307}}],\"TransactionIndex\":1,\"TransactionResult\":\"tesSUCCESS\"}}]"
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
{
"type": "amendment",
"address": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"sequence": 0,
"id": "A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F",
"specification": {
"amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE"
},
"outcome": {
"result": "tesSUCCESS",
"timestamp": "2016-05-05T16:33:30.000Z",
"fee": "0",
"balanceChanges": {},
"orderbookChanges": {},
"indexInLedger": 0
}
}

View File

@@ -0,0 +1,21 @@
{
"type": "feeUpdate",
"address": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"sequence": 0,
"id": "C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF",
"specification": {
"baseFeeXRP": "0.00001",
"referenceFeeUnits": 10,
"reserveBaseXRP": "50",
"reserveIncrementXRP": "12.5"
},
"outcome": {
"result": "tesSUCCESS",
"timestamp": "2014-08-08T16:57:50.000Z",
"fee": "0",
"balanceChanges": {},
"orderbookChanges": {},
"ledgerVersion": 3717633,
"indexInLedger": 3
}
}

View File

@@ -1,4 +1,4 @@
'use strict';
'use strict'; // eslint-disable-line strict
module.exports = {
generateAddress: require('./generate-address.json'),
@@ -43,7 +43,9 @@ module.exports = {
suspendedPaymentExecution:
require('./get-transaction-suspended-payment-execution.json'),
suspendedPaymentExecutionSimple:
require('./get-transaction-suspended-payment-execution-simple.json')
require('./get-transaction-suspended-payment-execution-simple.json'),
amendment: require('./get-transaction-amendment.json'),
feeUpdate: require('./get-transaction-fee-update.json')
},
getTransactions: {
normal: require('./get-transactions.json'),
@@ -57,7 +59,9 @@ module.exports = {
header: require('./get-ledger'),
full: require('./get-ledger-full'),
withSettingsTx: require('./get-ledger-with-settings-tx'),
withStateAsHashes: require('./get-ledger-with-state-as-hashes')
withStateAsHashes: require('./get-ledger-with-state-as-hashes'),
withPartial: require('./get-ledger-with-partial-payment'),
pre2014withPartial: require('./get-ledger-pre2014-with-partial')
},
prepareOrder: {
buy: require('./prepare-order.json'),

View File

@@ -1,5 +1,5 @@
{
"txJSON": "{\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10.1\"},\"TakerPays\":\"2000000\",\"Flags\":2148139008,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"txJSON": "{\"TransactionType\":\"OfferCreate\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"TakerGets\":{\"currency\":\"USD\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\",\"value\":\"10.1\"},\"TakerPays\":\"2000000\",\"Flags\":2148139008,\"Memos\":[{\"Memo\":{\"MemoData\":\"7465787465642064617461\",\"MemoType\":\"74657374\",\"MemoFormat\":\"706C61696E2F74657874\"}}],\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23,\"OfferSequence\":12345}",
"instructions": {
"fee": "0.000012",
"sequence": 23,

View File

@@ -1,4 +1,4 @@
'use strict'; // eslint-disable-line
'use strict'; // eslint-disable-line
module.exports = {
submit: {
@@ -10,7 +10,9 @@ module.exports = {
notFound: require('./ledger-not-found'),
withoutCloseTime: require('./ledger-without-close-time'),
withSettingsTx: require('./ledger-with-settings-tx'),
withStateAsHashes: require('./ledger-with-state-as-hashes')
withStateAsHashes: require('./ledger-with-state-as-hashes'),
withPartialPayment: require('./ledger-with-partial-payment'),
pre2014withPartial: require('./ledger-pre2014-with-partial')
},
empty: require('./empty'),
subscribe: require('./subscribe'),
@@ -33,6 +35,7 @@ module.exports = {
server_info: {
normal: require('./server-info'),
noValidated: require('./server-info-no-validated'),
syncing: require('./server-info-syncing'),
error: require('./server-info-error')
},
path_find: {
@@ -71,6 +74,8 @@ module.exports = {
require('./tx/suspended-payment-execution-simple.json'),
Unrecognized: require('./tx/unrecognized.json'),
NoMeta: require('./tx/no-meta.json'),
LedgerZero: require('./tx/ledger-zero.json')
LedgerZero: require('./tx/ledger-zero.json'),
Amendment: require('./tx/amendment.json'),
SetFee: require('./tx/set-fee.json')
}
};

View File

@@ -0,0 +1,141 @@
{
"id": 1,
"status": "success",
"type": "response",
"result": {
"ledger": {
"accepted": true,
"account_hash": "334EE5F2209538C3099E133D25725E5BFEB40A198EA7028E6317F13E95D533DF",
"close_flags": 0,
"close_time": 521225631,
"close_time_human": "2016-Jul-07 16:53:51",
"close_time_resolution": 10,
"closed": true,
"hash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"ledger_hash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"ledger_index": "12345",
"parent_close_time": 521225630,
"parent_hash": "4F636662B714CD9CCE965E9C23BB2E1058A2DF496F5A2416299317AE03F1CD35",
"seqNum": "22420574",
"totalCoins": "99997302532397566",
"total_coins": "99997302532397566",
"transaction_hash": "C72A2BDCB471F3AEEB917ABC6019407CAE6DA4B858903A8AB2335A0EB077125D",
"transactions": [
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"metaData": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Balance": "1930599790",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 23296
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
"PreviousFields": {
"Balance": "1930609790",
"Sequence": 23295
},
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
"PreviousTxnLgrSeq": 22419806
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-9.980959751659681"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000423"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-0.0009198315"
}
},
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
"PreviousTxnLgrSeq": 22420532
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276666.975959"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "00000000000002D7"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276676.975959"
}
},
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
"PreviousTxnLgrSeq": 22419307
}
}
],
"TransactionIndex": 1,
"TransactionResult": "tesSUCCESS"
}
}
]
},
"ledger_hash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"ledger_index": 12345,
"validated": true
}
}

View File

@@ -0,0 +1,600 @@
{
"id": 1,
"status": "success",
"type": "response",
"result": {
"ledger": {
"accepted": true,
"account_hash": "334EE5F2209538C3099E133D25725E5BFEB40A198EA7028E6317F13E95D533DF",
"close_flags": 0,
"close_time": 521225631,
"close_time_human": "2016-Jul-07 16:53:51",
"close_time_resolution": 10,
"closed": true,
"hash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"ledger_hash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"ledger_index": "22420574",
"parent_close_time": 521225630,
"parent_hash": "4F636662B714CD9CCE965E9C23BB2E1058A2DF496F5A2416299317AE03F1CD35",
"seqNum": "22420574",
"totalCoins": "99997302532397566",
"total_coins": "99997302532397566",
"transaction_hash": "C72A2BDCB471F3AEEB917ABC6019407CAE6DA4B858903A8AB2335A0EB077125D",
"transactions": [
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"metaData": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Balance": "1930599790",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 23296
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
"PreviousFields": {
"Balance": "1930609790",
"Sequence": 23295
},
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
"PreviousTxnLgrSeq": 22419806
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-9.980959751659681"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000423"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-0.0009198315"
}
},
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
"PreviousTxnLgrSeq": 22420532
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276666.975959"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "00000000000002D7"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276676.975959"
}
},
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
"PreviousTxnLgrSeq": 22419307
}
}
],
"DeliveredAmount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "9.980039920159681"
},
"TransactionIndex": 1,
"TransactionResult": "tesSUCCESS"
}
},
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"metaData": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Balance": "1930599790",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 23296
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
"PreviousFields": {
"Balance": "1930609790",
"Sequence": 23295
},
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
"PreviousTxnLgrSeq": 22419806
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-9.980959751659681"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000423"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-0.0009198315"
}
},
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
"PreviousTxnLgrSeq": 22420532
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276666.975959"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "00000000000002D7"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276676.975959"
}
},
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
"PreviousTxnLgrSeq": 22419307
}
}
],
"delivered_amount": "unavailable",
"TransactionIndex": 2,
"TransactionResult": "tesSUCCESS"
}
},
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"metaData": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Balance": "1930599790",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 23296
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
"PreviousFields": {
"Balance": "1930609790",
"Sequence": 23295
},
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
"PreviousTxnLgrSeq": 22419806
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-9.980959751659681"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000423"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-0.0009198315"
}
},
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
"PreviousTxnLgrSeq": 22420532
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276666.975959"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "00000000000002D7"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276676.975959"
}
},
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
"PreviousTxnLgrSeq": 22419307
}
}
],
"DeliveredAmount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "9.980039920159681"
},
"delivered_amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "9.980039920159681"
},
"TransactionIndex": 3,
"TransactionResult": "tesSUCCESS"
}
},
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 131072,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"metaData": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Balance": "1930599790",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 23296
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
"PreviousFields": {
"Balance": "1930609790",
"Sequence": 23295
},
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
"PreviousTxnLgrSeq": 22419806
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-9.980959751659681"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000423"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-0.0009198315"
}
},
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
"PreviousTxnLgrSeq": 22420532
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276666.975959"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "00000000000002D7"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276676.975959"
}
},
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
"PreviousTxnLgrSeq": 22419307
}
}
],
"TransactionIndex": 4,
"TransactionResult": "tesSUCCESS"
}
},
{
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Amount": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "10"
},
"Destination": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"Fee": "10000",
"Flags": 0,
"Sequence": 23295,
"SigningPubKey": "02B205F4B92351AC0EEB04254B636F4C49EF922CFA3CAAD03C6477DA1E04E94B53",
"TransactionType": "Payment",
"TxnSignature": "3045022100FAF247A836D601DE74A515B2AADE31186D8B0DA9C23DE489E09753F5CF4BB81F0220477C5B5BC3AC89F2347744F9E00CCA62267E198489D747578162C4C7D156211D",
"hash": "A0A074D10355223CBE2520A42F93A52E3CC8B4D692570EB4841084F9BBB39F7A",
"metaData": {
"AffectedNodes": [
{
"ModifiedNode": {
"FinalFields": {
"Account": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"Balance": "1930599790",
"Flags": 0,
"OwnerCount": 2,
"Sequence": 23296
},
"LedgerEntryType": "AccountRoot",
"LedgerIndex": "267C16D24EC42EEF8B03D5BE4E94266B1675FA54AFCE42DE795E02AB61031CBD",
"PreviousFields": {
"Balance": "1930609790",
"Sequence": 23295
},
"PreviousTxnID": "0F5396388E91D37BB26C8E24073A57E7C5D51E79AEE4CD855653B8499AE4E3DD",
"PreviousTxnLgrSeq": 22419806
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-9.980959751659681"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rNNuQMuExCiEjeZ4h9JJnj5PSWypdMXDj4",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "0000000000000423"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "C66957AF25229357F9C2D2BA17CE47D88169788EDA7610AD0F29AD5BCB225EE5",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-0.0009198315"
}
},
"PreviousTxnID": "2A01E994D7000000B43DD63825A081B4440A44AB2F6FA0D506158AC9CA6B2869",
"PreviousTxnLgrSeq": 22420532
}
},
{
"ModifiedNode": {
"FinalFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276666.975959"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rGFuMiw48HdbnrUbkRYuitXTmfrDBNTCnX",
"value": "1000000"
},
"HighNode": "0000000000000000",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "00000000000002D7"
},
"LedgerEntryType": "RippleState",
"LedgerIndex": "FFD710AE2074A98D920D00CC352F25744899F069A6C1B9E31DD32D2C6606E615",
"PreviousFields": {
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-276676.975959"
}
},
"PreviousTxnID": "BB9DFC87E9D4ED09CA2726DDFE83A4A396ED0D6545536322DE17CDACF45C0D5B",
"PreviousTxnLgrSeq": 22419307
}
}
],
"TransactionIndex": 5,
"TransactionResult": "tesSUCCESS"
}
}
]
},
"ledger_hash": "4F6C0495378FF68A15749C0D51D097EB638DA70319FDAC7A97A27CE63E0BFFED",
"validated": true
}
}

View File

@@ -0,0 +1,30 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"info": {
"build_version": "0.24.0-rc1",
"complete_ledgers": "32570-6595042",
"hostid": "ARTS",
"io_latency_ms": 1,
"last_close": {
"converge_time_s": 2.007,
"proposers": 4
},
"load_factor": 1,
"peers": 53,
"pubkey_node": "n94wWvFUmaKGYrKUGgpv1DyYgDeXRGdACkNQaSe7zJiy5Znio7UC",
"server_state": "syncing",
"validated_ledger": {
"age": 5,
"base_fee_xrp": 0.00001,
"hash": "4482DEE5362332F54A4036ED57EE1767C9F33CF7CE5A6670355C16CECE381D46",
"reserve_base_xrp": 20,
"reserve_inc_xrp": 5,
"seq": 6595042
},
"validation_quorum": 3
}
}
}

40
test/fixtures/rippled/tx/amendment.json vendored Normal file
View File

@@ -0,0 +1,40 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"Amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE",
"Fee": "0",
"Flags": 65536,
"date": 515781210,
"LedgerSequence": 20889601,
"Sequence": 0,
"SigningPubKey": "",
"TransactionType": "EnableAmendment",
"hash": "A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F",
"meta": {
"AffectedNodes": [
{
"CreatedNode": {
"LedgerEntryType": "Amendments",
"LedgerIndex": "7DB0788C020F02780A673DC74757F23823FA3014C1866E72CC4CD8B226CD6EF4",
"NewFields": {
"Majorities": [
{
"Majority": {
"Amendment": "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE",
"CloseTime": 515781202
}
}
]
}
}
}
],
"TransactionIndex": 0,
"TransactionResult": "tesSUCCESS"
},
"validated": true
}
}

43
test/fixtures/rippled/tx/set-fee.json vendored Normal file
View File

@@ -0,0 +1,43 @@
{
"id": 0,
"status": "success",
"type": "response",
"result": {
"hash": "C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF",
"ledger_index": 3717633,
"date": 460832270,
"TransactionType": "SetFee",
"Sequence": 0,
"ReferenceFeeUnits": 10,
"ReserveBase": 50000000,
"ReserveIncrement": 12500000,
"BaseFee": "000000000000000A",
"Fee": "0",
"SigningPubKey": "",
"Account": "rrrrrrrrrrrrrrrrrrrrrhoLvTp",
"meta": {
"TransactionIndex": 3,
"AffectedNodes": [
{
"ModifiedNode": {
"LedgerEntryType": "FeeSettings",
"LedgerIndex": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651",
"PreviousFields": {
"ReserveBase": 20000000,
"ReserveIncrement": 5000000
},
"FinalFields": {
"Flags": 0,
"ReferenceFeeUnits": 10,
"ReserveBase": 50000000,
"ReserveIncrement": 12500000,
"BaseFee": "000000000000000A"
}
}
}
],
"TransactionResult": "tesSUCCESS"
},
"validated": true
}
}

View File

@@ -1,4 +1,4 @@
'use strict'; // eslint-disable-line
'use strict'; // eslint-disable-line
const _ = require('lodash');
const assert = require('assert');
const WebSocketServer = require('ws').Server;
@@ -9,6 +9,7 @@ const hashes = require('./fixtures/hashes');
const transactionsResponse = require('./fixtures/rippled/account-tx');
const accountLinesResponse = require('./fixtures/rippled/account-lines');
const fullLedger = require('./fixtures/rippled/ledger-full-38129.json');
const {getFreePort} = require('./utils/net-utils');
function isUSD(json) {
return json === 'USD' || json === '0000000000000000000000005553440000000000';
@@ -46,7 +47,7 @@ function createLedgerResponse(request, response) {
return JSON.stringify(newResponse);
}
module.exports = function(port) {
module.exports = function createMockRippled(port) {
const mock = new WebSocketServer({port: port});
_.assign(mock, EventEmitter2.prototype);
@@ -71,6 +72,11 @@ module.exports = function(port) {
};
mock.on('connection', function(conn) {
if (mock.config.breakNextConnection) {
mock.config.breakNextConnection = false;
conn.terminate();
return;
}
this.socket = conn;
conn.config = {};
conn.on('message', function(requestJSON) {
@@ -107,6 +113,22 @@ module.exports = function(port) {
assert.strictEqual(request.command, 'test_command');
if (request.data.disconnectIn) {
setTimeout(conn.terminate.bind(conn), request.data.disconnectIn);
} else if (request.data.openOnOtherPort) {
getFreePort().then(newPort => {
createMockRippled(newPort);
conn.send(createResponse(request, {status: 'success', type: 'response',
result: {port: newPort}}
));
});
} else if (request.data.closeServerAndReopen) {
setTimeout(() => {
conn.terminate();
close.call(mock, () => {
setTimeout(() => {
createMockRippled(port);
}, request.data.closeServerAndReopen);
});
}, 10);
}
});
@@ -128,6 +150,9 @@ module.exports = function(port) {
conn.close();
} else if (conn.config.serverInfoWithoutValidated) {
conn.send(createResponse(request, fixtures.server_info.noValidated));
} else if (mock.config.returnSyncingServerInfo) {
mock.config.returnSyncingServerInfo--;
conn.send(createResponse(request, fixtures.server_info.syncing));
} else {
conn.send(createResponse(request, fixtures.server_info.normal));
}
@@ -180,6 +205,12 @@ module.exports = function(port) {
createLedgerResponse(request, fixtures.ledger.withoutCloseTime));
} else if (request.ledger_index === 4181996) {
conn.send(createLedgerResponse(request, fixtures.ledger.withSettingsTx));
} else if (request.ledger_index === 100000) {
conn.send(
createLedgerResponse(request, fixtures.ledger.withPartialPayment));
} else if (request.ledger_index === 100001) {
conn.send(
createLedgerResponse(request, fixtures.ledger.pre2014withPartial));
} else if (request.ledger_index === 38129) {
const response = _.assign({}, fixtures.ledger.normal,
{result: {ledger: fullLedger}});
@@ -267,6 +298,12 @@ module.exports = function(port) {
} else if (request.transaction ===
'4FB3ADF22F3C605E23FAEFAA185F3BD763C4692CAC490D9819D117CD33BFAA13') {
conn.send(createResponse(request, fixtures.tx.LedgerZero));
} else if (request.transaction ===
'A971B83ABED51D83749B73F3C1AAA627CD965AFF74BE8CD98299512D6FB0658F') {
conn.send(createResponse(request, fixtures.tx.Amendment));
} else if (request.transaction ===
'C6A40F56127436DCD830B1B35FF939FD05B5747D30D6542572B7A835239817AF') {
conn.send(createResponse(request, fixtures.tx.SetFee));
} else {
assert(false, 'Unrecognized transaction hash: ' + request.transaction);
}

View File

@@ -1,5 +1,5 @@
/* eslint-disable max-nested-callbacks */
'use strict';
'use strict'; // eslint-disable-line
const {RippleAPI, RippleAPIBroadcast} = require('ripple-api');
const ledgerClosed = require('./fixtures/rippled/ledger-close');
@@ -8,12 +8,22 @@ const port = 34371;
const baseUrl = 'ws://testripple.circleci.com:';
function setup(port_ = port) {
return new Promise((resolve, reject) => {
this.api = new RippleAPI({server: baseUrl + port_});
this.api.connect().then(() => {
this.api.once('ledger', () => resolve());
this.api.connection._ws.emit('message', JSON.stringify(ledgerClosed));
}).catch(reject);
const tapi = new RippleAPI({server: baseUrl + port_});
return tapi.connect().then(() => {
return tapi.connection.request({
command: 'test_command',
data: {openOnOtherPort: true}
});
}).then(got => {
return new Promise((resolve, reject) => {
this.api = new RippleAPI({server: baseUrl + got.port});
this.api.connect().then(() => {
this.api.once('ledger', () => resolve());
this.api.connection._ws.emit('message', JSON.stringify(ledgerClosed));
}).catch(reject);
});
}).then(() => {
return tapi.disconnect();
});
}
@@ -33,6 +43,7 @@ function teardown() {
if (this.api.isConnected()) {
return this.api.disconnect();
}
return undefined;
}
module.exports = {

View File

@@ -1,29 +1,11 @@
'use strict'; // eslint-disable-line
const net = require('net');
const RippleAPI = require('ripple-api').RippleAPI;
const RippleAPIBroadcast = require('ripple-api').RippleAPIBroadcast;
const ledgerClosed = require('./fixtures/rippled/ledger-close');
const createMockRippled = require('./mock-rippled');
const {getFreePort} = require('./utils/net-utils');
// using a free port instead of a constant port enables parallelization
function getFreePort() {
return new Promise((resolve, reject) => {
const server = net.createServer();
let port;
server.on('listening', function() {
port = server.address().port;
server.close();
});
server.on('close', function() {
resolve(port);
});
server.on('error', function(error) {
reject(error);
});
server.listen(0);
});
}
function setupMockRippledConnection(testcase, port) {
return new Promise((resolve, reject) => {

26
test/utils/net-utils.js Normal file
View File

@@ -0,0 +1,26 @@
'use strict'; // eslint-disable-line
const net = require('net');
// using a free port instead of a constant port enables parallelization
function getFreePort() {
return new Promise((resolve, reject) => {
const server = net.createServer();
let port;
server.on('listening', function() {
port = server.address().port;
server.close();
});
server.on('close', function() {
resolve(port);
});
server.on('error', function(error) {
reject(error);
});
server.listen(0);
});
}
module.exports = {
getFreePort
};