mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-12 08:35:48 +00:00
Compare commits
88 Commits
0.10.0-rc1
...
0.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a05833f845 | ||
|
|
c5deb60510 | ||
|
|
2cab50f920 | ||
|
|
b049278dde | ||
|
|
93335e74cb | ||
|
|
0d05b960f7 | ||
|
|
9fd64a9209 | ||
|
|
1637d26de3 | ||
|
|
525ff9b75e | ||
|
|
42e7932f59 | ||
|
|
98f40abfc3 | ||
|
|
55cd13ed4e | ||
|
|
7cb113fcbc | ||
|
|
ddbb999194 | ||
|
|
1db96829ed | ||
|
|
3498dea18c | ||
|
|
97a8c87490 | ||
|
|
fa72e09840 | ||
|
|
d8cad710a5 | ||
|
|
f91dcc33d3 | ||
|
|
e5f524ec56 | ||
|
|
f9b13cbc7f | ||
|
|
c7e0ba68f6 | ||
|
|
220262d192 | ||
|
|
1f860ecba6 | ||
|
|
69a13b71ea | ||
|
|
0a27afe6ee | ||
|
|
a3de021cd2 | ||
|
|
4dcbe78e83 | ||
|
|
84a8e8cbf6 | ||
|
|
e4b2b3d06b | ||
|
|
000a2ea00c | ||
|
|
89de91301e | ||
|
|
6be84bfa73 | ||
|
|
6cd79e7237 | ||
|
|
11d73173b8 | ||
|
|
9b3d62b765 | ||
|
|
2bdff53e68 | ||
|
|
8af5f9c28e | ||
|
|
9f71abf978 | ||
|
|
3fc2d3c1d9 | ||
|
|
c0c8db6dcc | ||
|
|
27249c0bb4 | ||
|
|
62e9684542 | ||
|
|
74b006cb0b | ||
|
|
77b33f11ab | ||
|
|
0aba638e6e | ||
|
|
e82522349f | ||
|
|
e520700260 | ||
|
|
3ec335f3a6 | ||
|
|
0f212e4dd1 | ||
|
|
c263654c88 | ||
|
|
874e3f24a6 | ||
|
|
b14343f3cf | ||
|
|
732b50dea7 | ||
|
|
be3bbe9b61 | ||
|
|
51211bbba0 | ||
|
|
5d1ff1c912 | ||
|
|
ea1be4fc50 | ||
|
|
7cc05f0d92 | ||
|
|
54606f3c21 | ||
|
|
a5d1705930 | ||
|
|
bfc0fb6c88 | ||
|
|
d1d4452217 | ||
|
|
2166a434a3 | ||
|
|
1053fa18e1 | ||
|
|
fa147d467e | ||
|
|
3f61598d6c | ||
|
|
9bf3724ce6 | ||
|
|
c2f27a4deb | ||
|
|
b6b99dde02 | ||
|
|
1fd0f4a8fe | ||
|
|
67d39737a4 | ||
|
|
aef4fe29a3 | ||
|
|
34c0677c45 | ||
|
|
3cb4a64b47 | ||
|
|
0db0375a5e | ||
|
|
47e6bdc644 | ||
|
|
66c2e27711 | ||
|
|
72387873b4 | ||
|
|
59017bc0bd | ||
|
|
2dde114d3d | ||
|
|
9e89904f03 | ||
|
|
56d0aca254 | ||
|
|
239710cebf | ||
|
|
1eaad617cb | ||
|
|
3c21994adc | ||
|
|
d15d14e197 |
7
.flowconfig
Normal file
7
.flowconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
[ignore]
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
|
||||
[options]
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -25,6 +25,7 @@ Release/*.*
|
||||
|
||||
# Ignore locally installed node_modules
|
||||
node_modules
|
||||
!test/node_modules
|
||||
|
||||
# Ignore tmp directory.
|
||||
tmp
|
||||
@@ -52,3 +53,9 @@ npm-debug.log
|
||||
|
||||
# Ignore dist folder, build for bower
|
||||
dist/
|
||||
|
||||
# Ignore flow output directory
|
||||
out/
|
||||
|
||||
# Ignore perf test cache
|
||||
scripts/cache
|
||||
|
||||
58
Gulpfile.js
58
Gulpfile.js
@@ -1,11 +1,18 @@
|
||||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var watch = require('gulp-watch');
|
||||
var plumber = require('gulp-plumber');
|
||||
var filelog = require('gulp-filelog');
|
||||
var cleanDest = require('gulp-clean-dest');
|
||||
var concat = require('gulp-concat');
|
||||
var uglify = require('gulp-uglify');
|
||||
var rename = require('gulp-rename');
|
||||
var webpack = require('webpack');
|
||||
var jshint = require('gulp-jshint');
|
||||
var eslint = require('gulp-eslint');
|
||||
var map = require('map-stream');
|
||||
var bump = require('gulp-bump');
|
||||
var react = require('gulp-react');
|
||||
var flow = require('gulp-flowtype');
|
||||
var argv = require('yargs').argv;
|
||||
//var header = require('gulp-header');
|
||||
|
||||
@@ -50,6 +57,10 @@ var sjclSrc = [
|
||||
'src/js/sjcl-custom/sjcl-jacobi.js'
|
||||
];
|
||||
|
||||
function logPluginError(error) {
|
||||
gutil.log(error.toString());
|
||||
}
|
||||
|
||||
gulp.task('concat-sjcl', function() {
|
||||
return gulp.src(sjclSrc)
|
||||
.pipe(concat('sjcl.js'))
|
||||
@@ -150,35 +161,34 @@ gulp.task('bower-version', function() {
|
||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug', 'bower-version']);
|
||||
|
||||
gulp.task('lint', function() {
|
||||
gulp.src('src/js/ripple/*.js')
|
||||
.pipe(jshint())
|
||||
.pipe(map(function(file, callback) {
|
||||
if (!file.jshint.success) {
|
||||
console.log('\nIn', file.path);
|
||||
|
||||
file.jshint.results.forEach(function(err) {
|
||||
if (err && err.error) {
|
||||
var col1 = err.error.line + ':' + err.error.character;
|
||||
var col2 = '[' + err.error.reason + ']';
|
||||
var col3 = '(' + err.error.code + ')';
|
||||
|
||||
while (col1.length < 8) {
|
||||
col1 += ' ';
|
||||
}
|
||||
|
||||
console.log(' ' + [ col1, col2, col3 ].join(' '));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
callback(null, file);
|
||||
}));
|
||||
return gulp.src('src/js/ripple/*.js')
|
||||
.pipe(eslint({ reset: true, configFile: './eslint.json' }))
|
||||
.pipe(eslint.format());
|
||||
});
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch('src/js/ripple/*', [ 'build-debug' ]);
|
||||
});
|
||||
|
||||
// To use this, each javascript file must have /* @flow */ on the first line
|
||||
gulp.task('typecheck', function() {
|
||||
return gulp.src('src/js/ripple/*.js')
|
||||
.pipe(flow({ // note: do not set the 'all' option, it is broken
|
||||
weak: true, // remove this after all errors are addressed
|
||||
killFlow: true
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('strip', function() {
|
||||
return gulp.src('src/js/ripple/*.js')
|
||||
.pipe(watch('src/js/ripple/*.js'))
|
||||
.pipe(cleanDest('out')) // delete outdated output file before stripping
|
||||
.pipe(plumber()) // prevent an error in one file from ending build
|
||||
.pipe(react({ stripTypes: true }).on('error', logPluginError))
|
||||
.pipe(filelog())
|
||||
.pipe(gulp.dest('out'));
|
||||
});
|
||||
|
||||
gulp.task('version-bump', function() {
|
||||
if (!argv.type) {
|
||||
throw new Error("No type found, pass it in using the --type argument");
|
||||
|
||||
29
HISTORY.md
29
HISTORY.md
@@ -1,3 +1,28 @@
|
||||
##0.11.0
|
||||
|
||||
+ [Track the funded status of an order based on cumulative account orders](https://github.com/ripple/ripple-lib/commit/67d39737a4d5e0fcd9d9b47b9083ee00e5a9e652) and [67d3973](https://github.com/ripple/ripple-lib/commit/b6b99dde022e1e14c4797e454b1d7fca50e49482)
|
||||
|
||||
+ Remove blobvault client from ripple-lib, use the [`ripple-vault-client`](https://github.com/ripple/ripple-vault-client) instead [9b3d62b7](https://github.com/ripple/ripple-lib/commit/9b3d62b765c4c25beae6eb0fa57ef3a07f2581b1)
|
||||
|
||||
+ [Add support for `ledger` option in requestBookOffers](https://github.com/ripple/ripple-lib/commit/34c0677c453c409ef0a5b351959abdc176d3bacb)
|
||||
|
||||
+ [Add support for `limit` option in requestBookOffers](https://github.com/ripple/ripple-lib/commit/d1d4452217c878d0b377d24830b4cd8b3162f6e0)
|
||||
|
||||
+ [Add `ledgerSelect` request constructor in `Remote`](https://github.com/ripple/ripple-lib/commit/98f40abfc3aa74dec5067a2d90002756cc8acd01)
|
||||
|
||||
+ [Default to binary data for commands that accept the binary flag](https://github.com/ripple/ripple-lib/commit/7cb113fcbcfc1e3e9830a999148b3e78df3387cc)
|
||||
|
||||
+ [Fix metadata account check](https://github.com/ripple/ripple-lib/commit/3f61598d6c87e3cc877af60e2d515f9eff73dfe1)
|
||||
|
||||
+ [Double check `tes` code before emitting `success`](https://github.com/ripple/ripple-lib/commit/97a8c874903eb7309d8f755955ac80872f670582)
|
||||
|
||||
+ [Decrease redundancy in binary account_tx parsing](https://github.com/ripple/ripple-lib/commit/0aba638e6e7f4f6e22cb6424eed3897ebad90a5a)
|
||||
|
||||
+ [Abort server connection on unrecoverable TLS error](https://github.com/ripple/ripple-lib/commit/000a2ea00c57157044aeca0fb3f24b37669b163c)
|
||||
|
||||
+ [Fix complete ledgers check on subscription that is not initial](https://github.com/ripple/ripple-lib/commit/89de91301e682a46dc60aaacc7ae152e8fe1b7c7)
|
||||
|
||||
|
||||
##0.10.0
|
||||
|
||||
+ [Transaction changes](https://github.com/ripple/ripple-lib/pull/221)
|
||||
@@ -21,7 +46,9 @@ are locally determined to have expired: `tejMaxLedger`.
|
||||
+ [Update jscl library](https://github.com/ripple/ripple-lib/commit/3204998fcb6f31d6c90532a737a4adb8a1e420f6)
|
||||
- Improved entropy by taking advantage of platform crypto
|
||||
- Use jscl's k256 curve instead of altering the c256 curve with k256 configuration
|
||||
- **deprecated:** the c256 curve is linked to the k256 curve to provide backwards compatibility, this link will be removed in the future
|
||||
- **deprecated:** the c256 curve is linked to the k256 curve to provide backwards compatibility, this link will be removed in the future
|
||||
|
||||
+ [Fix empty queue check on reconnect](https://github.com/ripple/ripple-lib/commit/3c21994adcf72d1fbd87d453ceb917f9ad6df4ec)
|
||||
|
||||
##0.9.4
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ A JavaScript API for interacting with Ripple in Node.js and the browser
|
||||
###Features
|
||||
|
||||
+ Connect to a rippled server in JavaScript (Node.js or browser)
|
||||
+ Issue [rippled API](https://ripple.com/wiki/JSON_Messages) requests
|
||||
+ Issue [rippled API](https://ripple.com/build/rippled-apis/) requests
|
||||
+ Listen to events on the Ripple network (transaction, ledger, etc.)
|
||||
+ Sign and submit transactions to the Ripple network
|
||||
|
||||
|
||||
20
docs/BUILD.md
Normal file
20
docs/BUILD.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Using Flow typechecking
|
||||
=======================
|
||||
|
||||
Stage 1
|
||||
-------
|
||||
1. Add /* @flow */ to the top of a file you want to typecheck
|
||||
2. Run `gulp typecheck` to generate a list of warnings
|
||||
|
||||
Stage 2
|
||||
-------
|
||||
When all source files have the /* @flow */ header and all warnings have been
|
||||
addressed, remove the `weak: true` option from Gulpfile.js, run
|
||||
`gulp typecheck` and remove all the additional warnings.
|
||||
|
||||
Stage 3
|
||||
-------
|
||||
Add type annotations to the source code and run `gulp strip` to strip
|
||||
the type annotations and write the output to the `out` directory. After
|
||||
type annotations are added, the program must be run from the `out` directory
|
||||
because Node does not understand the annotations
|
||||
@@ -39,7 +39,7 @@ This file provides step-by-step walkthroughs for some of the most common usages
|
||||
]
|
||||
}
|
||||
|
||||
var remote = new Remote({options});
|
||||
var remote = new Remote(options);
|
||||
|
||||
remote.connect(function(err, res) {
|
||||
/* remote connected, use some remote functions here */
|
||||
|
||||
73
eslint.json
Normal file
73
eslint.json
Normal file
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"no-use-before-define": 1,
|
||||
"no-undef": 1,
|
||||
"no-unused-expressions": 1,
|
||||
"no-unused-vars": 1,
|
||||
"no-extend-native": 1,
|
||||
"no-native-reassign": 1,
|
||||
"no-trailing-spaces": 1,
|
||||
"no-empty": 1,
|
||||
"no-inner-declarations": 1,
|
||||
"no-irregular-whitespace": 1,
|
||||
"no-negated-in-lhs": 1,
|
||||
"no-obj-calls": 1,
|
||||
"no-reserved-keys": 1,
|
||||
"no-sparse-arrays": 1,
|
||||
"no-unreachable": 1,
|
||||
"use-isnan": 1,
|
||||
"valid-jsdoc": 1,
|
||||
"valid-typeof": 1,
|
||||
"block-scoped-var": 1,
|
||||
"dot-notation": 1,
|
||||
"semi": 1,
|
||||
"curly": 1,
|
||||
"eqeqeq": 1,
|
||||
"no-else-return": 1,
|
||||
"new-cap": 1,
|
||||
"new-parens": 1,
|
||||
"no-comma-dangle": 1,
|
||||
"no-empty-label": 1,
|
||||
"no-eval": 1,
|
||||
"no-extra-bind": 1,
|
||||
"no-fallthrough": 1,
|
||||
"no-lone-blocks": 1,
|
||||
"no-loop-func": 1,
|
||||
"no-multi-spaces": 1,
|
||||
"no-return-assign": 1,
|
||||
"no-sequences": 1,
|
||||
"no-with": 1,
|
||||
"radix": 1,
|
||||
"yoda": [ 1, "never" ],
|
||||
"no-catch-shadow": 1,
|
||||
"no-shadow-restricted-names": 1,
|
||||
"no-delete-var": 1,
|
||||
"no-undefined": 1,
|
||||
"handle-callback-err": 1,
|
||||
"brace-style": [ 1, "1tbs", { "allowSingleLine": false } ],
|
||||
"comma-spacing": [ 1, { "before": false, "after": true } ],
|
||||
"comma-style": [ 1, "last" ],
|
||||
"consistent-this": [ 1, "self" ],
|
||||
"func-style": [ 1, "declaration" ],
|
||||
"key-spacing": [ 1, { "beforeColon": false, "afterColon": true } ],
|
||||
"max-nested-callbacks": [ 1, 2 ],
|
||||
"no-lonely-if": 1,
|
||||
"no-mixed-spaces-and-tabs": 1,
|
||||
"no-multiple-empty-lines": 1,
|
||||
"no-space-before-semi": 1,
|
||||
"no-spaced-func": 1,
|
||||
"space-after-keywords": [ 1, "always" ],
|
||||
"space-in-brackets": [ 1, "always" ],
|
||||
"space-infix-ops": 1,
|
||||
"space-return-throw-case": 1,
|
||||
"spaced-line-comment": 1,
|
||||
"max-params": [ 1, 4 ],
|
||||
"max-depth": [1, 3 ],
|
||||
"max-len": [ 1, 80 ],
|
||||
"quotes": [ 1, "single" ]
|
||||
}
|
||||
}
|
||||
78
npm-shrinkwrap.json
generated
78
npm-shrinkwrap.json
generated
@@ -1,116 +1,132 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.10.0-rc1",
|
||||
"version": "0.11.0",
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "0.8.0",
|
||||
"from": "async@>=0.8.0 <0.9.0"
|
||||
"from": "https://registry.npmjs.org/async/-/async-0.8.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.8.0.tgz"
|
||||
},
|
||||
"extend": {
|
||||
"version": "1.2.1",
|
||||
"from": "extend@>=1.2.1 <1.3.0"
|
||||
"from": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
||||
},
|
||||
"lodash": {
|
||||
"version": "2.4.1",
|
||||
"from": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz"
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "2.5.0",
|
||||
"from": "lru-cache@>=2.5.0 <2.6.0"
|
||||
"from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz"
|
||||
},
|
||||
"ripple-wallet-generator": {
|
||||
"version": "1.0.1",
|
||||
"from": "ripple-wallet-generator@1.0.1",
|
||||
"from": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.1.tgz"
|
||||
},
|
||||
"superagent": {
|
||||
"version": "0.18.2",
|
||||
"from": "superagent@>=0.18.0 <0.19.0",
|
||||
"from": "https://registry.npmjs.org/superagent/-/superagent-0.18.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/superagent/-/superagent-0.18.2.tgz",
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "0.6.6",
|
||||
"from": "qs@0.6.6",
|
||||
"from": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz"
|
||||
},
|
||||
"formidable": {
|
||||
"version": "1.0.14",
|
||||
"from": "formidable@1.0.14",
|
||||
"from": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz",
|
||||
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz"
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.2.11",
|
||||
"from": "mime@1.2.11",
|
||||
"from": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz"
|
||||
},
|
||||
"component-emitter": {
|
||||
"version": "1.1.2",
|
||||
"from": "component-emitter@1.1.2",
|
||||
"from": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz"
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.0.1",
|
||||
"from": "methods@1.0.1",
|
||||
"from": "https://registry.npmjs.org/methods/-/methods-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.0.1.tgz"
|
||||
},
|
||||
"cookiejar": {
|
||||
"version": "2.0.1",
|
||||
"from": "cookiejar@2.0.1",
|
||||
"from": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.0.1.tgz"
|
||||
},
|
||||
"debug": {
|
||||
"version": "1.0.4",
|
||||
"from": "debug@>=1.0.1 <1.1.0",
|
||||
"from": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "0.6.2",
|
||||
"from": "ms@0.6.2",
|
||||
"from": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"reduce-component": {
|
||||
"version": "1.0.1",
|
||||
"from": "reduce-component@1.0.1",
|
||||
"from": "https://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz"
|
||||
},
|
||||
"form-data": {
|
||||
"version": "0.1.3",
|
||||
"from": "form-data@0.1.3",
|
||||
"from": "https://registry.npmjs.org/form-data/-/form-data-0.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.3.tgz",
|
||||
"dependencies": {
|
||||
"combined-stream": {
|
||||
"version": "0.0.5",
|
||||
"from": "combined-stream@>=0.0.4 <0.1.0",
|
||||
"version": "0.0.7",
|
||||
"from": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz",
|
||||
"dependencies": {
|
||||
"delayed-stream": {
|
||||
"version": "0.0.5",
|
||||
"from": "delayed-stream@0.0.5",
|
||||
"from": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"async": {
|
||||
"version": "0.9.0",
|
||||
"from": "async@>=0.9.0 <0.10.0"
|
||||
"from": "https://registry.npmjs.org/async/-/async-0.9.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.0.27-1",
|
||||
"from": "readable-stream@1.0.27-1",
|
||||
"from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.27-1.tgz",
|
||||
"dependencies": {
|
||||
"core-util-is": {
|
||||
"version": "1.0.1",
|
||||
"from": "core-util-is@>=1.0.0 <1.1.0"
|
||||
"from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz"
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"from": "isarray@0.0.1",
|
||||
"from": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"from": "string_decoder@>=0.10.0 <0.11.0"
|
||||
"from": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1",
|
||||
"from": "inherits@>=2.0.1 <2.1.0"
|
||||
"from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,23 +134,25 @@
|
||||
},
|
||||
"ws": {
|
||||
"version": "0.4.32",
|
||||
"from": "ws@>=0.4.31 <0.5.0",
|
||||
"from": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz",
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.1.0",
|
||||
"from": "commander@>=2.1.0 <2.2.0"
|
||||
"from": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz"
|
||||
},
|
||||
"nan": {
|
||||
"version": "1.0.0",
|
||||
"from": "nan@>=1.0.0 <1.1.0"
|
||||
"from": "nan@1.0.0"
|
||||
},
|
||||
"tinycolor": {
|
||||
"version": "0.0.1",
|
||||
"from": "tinycolor@>=0.0.0 <1.0.0"
|
||||
"from": "tinycolor@0.0.1"
|
||||
},
|
||||
"options": {
|
||||
"version": "0.0.6",
|
||||
"from": "options@>=0.0.5"
|
||||
"from": "options@0.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
42
package.json
42
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.10.0-rc1",
|
||||
"version": "0.11.0",
|
||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||
"files": [
|
||||
"src/js/*",
|
||||
@@ -16,32 +16,42 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.8.0",
|
||||
"ws": "~0.4.31",
|
||||
"extend": "~1.2.1",
|
||||
"lodash": "^2.4.1",
|
||||
"lru-cache": "~2.5.0",
|
||||
"superagent": "^0.18.0",
|
||||
"ripple-wallet-generator": "1.0.1"
|
||||
"ripple-wallet-generator": "1.0.1",
|
||||
"ws": "~0.4.31",
|
||||
"superagent": "^0.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.14.0",
|
||||
"gulp": "~3.6.2",
|
||||
"gulp-concat": "~2.2.0",
|
||||
"gulp-jshint": "~1.5.5",
|
||||
"gulp-uglify": "~0.3.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-bump": "~0.1.10",
|
||||
"webpack": "~1.1.11",
|
||||
"map-stream": "~0.1.0",
|
||||
"istanbul": "~0.2.10",
|
||||
"coveralls": "~2.10.0",
|
||||
"gulp": "~3.6.2",
|
||||
"gulp-bump": "~0.1.10",
|
||||
"gulp-clean-dest": "^0.1.0",
|
||||
"gulp-concat": "~2.2.0",
|
||||
"gulp-filelog": "^0.4.1",
|
||||
"gulp-flowtype": "^0.4.1",
|
||||
"gulp-plumber": "^0.6.6",
|
||||
"gulp-react": "^2.0.0",
|
||||
"gulp-rename": "~1.2.0",
|
||||
"gulp-uglify": "~0.3.0",
|
||||
"gulp-util": "^3.0.2",
|
||||
"gulp-watch": "^3.0.0",
|
||||
"gulp-eslint": "^0.2.0",
|
||||
"istanbul": "~0.2.10",
|
||||
"map-stream": "~0.1.0",
|
||||
"mocha": "~1.14.0",
|
||||
"nock": "^0.34.1",
|
||||
"webpack": "~1.1.11",
|
||||
"yargs": "~1.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node_modules/.bin/gulp",
|
||||
"pretest": "node_modules/.bin/gulp concat-sjcl",
|
||||
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter spec test/*-test.js",
|
||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls"
|
||||
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter tap test/*-test.js",
|
||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
|
||||
"lint": "./node_modules/.bin/gulp lint",
|
||||
"perf": "./scripts/perf_test.sh"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
11
scripts/perf_test.sh
Executable file
11
scripts/perf_test.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
URL="https://www.dropbox.com/s/a0gy7vbb86eeqlq/ledger-full-1000000.json?dl=1"
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
DEST="$DIR/cache/ledger-full-1000000.json"
|
||||
if [ ! -e "$DEST" ]
|
||||
then
|
||||
echo "Downloading test data..."
|
||||
mkdir -p "$DIR/cache"
|
||||
curl -L "$URL" > "$DEST"
|
||||
fi
|
||||
time node "$DIR/verify_ledger_json.js" "$DEST"
|
||||
@@ -45,7 +45,7 @@ function Account(remote, account) {
|
||||
if (!self._subs && self._remote._connected) {
|
||||
self._remote.request_subscribe()
|
||||
.add_account(self._account_id)
|
||||
.broadcast();
|
||||
.broadcast().request();
|
||||
}
|
||||
self._subs += 1;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ function Account(remote, account) {
|
||||
if (!self._subs && self._remote._connected) {
|
||||
self._remote.request_unsubscribe()
|
||||
.add_account(self._account_id)
|
||||
.broadcast();
|
||||
.broadcast().request();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
var async = require('async');
|
||||
var superagent = require('superagent');
|
||||
var RippleTxt = require('./rippletxt').RippleTxt;
|
||||
|
||||
var AuthInfo = { };
|
||||
|
||||
AuthInfo._getRippleTxt = function(domain, callback) {
|
||||
RippleTxt.get(domain, callback);
|
||||
};
|
||||
|
||||
AuthInfo._getUser = function(url, callback) {
|
||||
superagent.get(url, callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get auth info for a given username
|
||||
*
|
||||
* @param {string} domain - Domain which hosts the user's info
|
||||
* @param {string} username - Username who's info we are retreiving
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
AuthInfo.get = function(domain, username, callback) {
|
||||
var self = this;
|
||||
username = username.toLowerCase();
|
||||
|
||||
function getRippleTxt(callback) {
|
||||
self._getRippleTxt(domain, function(err, txt) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!txt.authinfo_url) {
|
||||
return callback(new Error('Authentication is not supported on ' + domain));
|
||||
}
|
||||
|
||||
var url = Array.isArray(txt.authinfo_url) ? txt.authinfo_url[0] : txt.authinfo_url;
|
||||
|
||||
url += '?domain=' + domain + '&username=' + username;
|
||||
|
||||
callback(null, url);
|
||||
});
|
||||
};
|
||||
|
||||
function getUser(url, callback) {
|
||||
self._getUser(url, function(err, res) {
|
||||
if (err || res.error) {
|
||||
callback(new Error('Authentication info server unreachable'));
|
||||
} else {
|
||||
callback(null, res.body);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
async.waterfall([ getRippleTxt, getUser ], callback);
|
||||
};
|
||||
|
||||
exports.AuthInfo = AuthInfo;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ exports.Account = require('./account').Account;
|
||||
exports.Transaction = require('./transaction').Transaction;
|
||||
exports.Currency = require('./currency').Currency;
|
||||
exports.Base = require('./base').Base;
|
||||
exports.UInt128 = require('./uint128').UInt128;
|
||||
exports.UInt160 = require('./uint160').UInt160;
|
||||
exports.UInt256 = require('./uint256').UInt256;
|
||||
exports.Seed = require('./seed').Seed;
|
||||
@@ -12,13 +13,13 @@ exports.Meta = require('./meta').Meta;
|
||||
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
||||
exports.RippleError = require('./rippleerror').RippleError;
|
||||
exports.Message = require('./message').Message;
|
||||
exports.VaultClient = require('./vaultclient').VaultClient;
|
||||
exports.AuthInfo = require('./authinfo').AuthInfo;
|
||||
exports.RippleTxt = require('./rippletxt').RippleTxt;
|
||||
exports.binformat = require('./binformat');
|
||||
exports.utils = require('./utils');
|
||||
exports.Server = require('./server').Server;
|
||||
exports.Wallet = require('./wallet');
|
||||
exports.Ledger = require('./ledger').Ledger;
|
||||
exports.TransactionQueue = require('./transactionqueue').TransactionQueue;
|
||||
exports.RangeSet = require('./rangeset').RangeSet;
|
||||
|
||||
// Important: We do not guarantee any specific version of SJCL or for any
|
||||
// specific features to be included. The version and configuration may change at
|
||||
@@ -28,6 +29,8 @@ exports.Wallet = require('./wallet');
|
||||
// the official client, it makes sense to expose the SJCL instance so we don't
|
||||
// have to include it twice.
|
||||
exports.sjcl = require('./utils').sjcl;
|
||||
exports.jsbn = require('./utils').jsbn;
|
||||
exports.types = require('./serializedtypes');
|
||||
|
||||
exports.config = require('./config');
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var extend = require('extend');
|
||||
var utils = require('./utils');
|
||||
var utils = require('./utils');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Amount = require('./amount').Amount;
|
||||
|
||||
@@ -26,28 +26,37 @@ function Meta(data) {
|
||||
data.AffectedNodes.forEach(this.addNode, this);
|
||||
};
|
||||
|
||||
Meta.nodeTypes = [
|
||||
Meta.NODE_TYPES = [
|
||||
'CreatedNode',
|
||||
'ModifiedNode',
|
||||
'DeletedNode'
|
||||
];
|
||||
|
||||
Meta.amountFieldsAffectingIssuer = [
|
||||
Meta.AMOUNT_FIELDS_AFFECTING_ISSUER = [
|
||||
'LowLimit',
|
||||
'HighLimit',
|
||||
'TakerPays',
|
||||
'TakerGets'
|
||||
];
|
||||
|
||||
Meta.ACCOUNT_FIELDS = [
|
||||
'Account',
|
||||
'Owner',
|
||||
'Destination',
|
||||
'Issuer',
|
||||
'Target'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {Object} node
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Meta.prototype.getNodeType = function(node) {
|
||||
var result = null;
|
||||
|
||||
for (var i=0; i<Meta.nodeTypes.length; i++) {
|
||||
var type = Meta.nodeTypes[i];
|
||||
for (var i=0; i<Meta.NODE_TYPES.length; i++) {
|
||||
var type = Meta.NODE_TYPES[i];
|
||||
if (node.hasOwnProperty(type)) {
|
||||
result = type;
|
||||
break;
|
||||
@@ -57,6 +66,15 @@ Meta.prototype.getNodeType = function(node) {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} field
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Meta.prototype.isAccountField = function(field) {
|
||||
return Meta.ACCOUNT_FIELDS.indexOf(field) !== -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add node to metadata
|
||||
*
|
||||
@@ -72,7 +90,6 @@ Meta.prototype.addNode = function(node) {
|
||||
|
||||
if ((result.nodeType = this.getNodeType(node))) {
|
||||
node = node[result.nodeType];
|
||||
|
||||
result.diffType = result.nodeType;
|
||||
result.entryType = node.LedgerEntryType;
|
||||
result.ledgerIndex = node.LedgerIndex;
|
||||
@@ -114,56 +131,6 @@ Meta.prototype.getNodes = function(options) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a function on each affected node.
|
||||
*
|
||||
* The callback is passed two parameters. The first is a node object which looks
|
||||
* like this:
|
||||
*
|
||||
* {
|
||||
* // Type of diff, e.g. CreatedNode, ModifiedNode
|
||||
* nodeType: 'CreatedNode'
|
||||
*
|
||||
* // Type of node affected, e.g. RippleState, AccountRoot
|
||||
* entryType: 'RippleState',
|
||||
*
|
||||
* // Index of the ledger this change occurred in
|
||||
* ledgerIndex: '01AB01AB...',
|
||||
*
|
||||
* // Contains all fields with later versions taking precedence
|
||||
* //
|
||||
* // This is a shorthand for doing things like checking which account
|
||||
* // this affected without having to check the nodeType.
|
||||
* fields: {...},
|
||||
*
|
||||
* // Old fields (before the change)
|
||||
* fieldsPrev: {...},
|
||||
*
|
||||
* // New fields (that have been added)
|
||||
* fieldsNew: {...},
|
||||
*
|
||||
* // Changed fields
|
||||
* fieldsFinal: {...}
|
||||
* }
|
||||
*
|
||||
* The second parameter to the callback is the index of the node in the metadata
|
||||
* (first entry is index 0).
|
||||
*/
|
||||
|
||||
[
|
||||
'forEach',
|
||||
'map',
|
||||
'filter',
|
||||
'every',
|
||||
'some',
|
||||
'reduce'
|
||||
].forEach(function(fn) {
|
||||
Meta.prototype[fn] = function() {
|
||||
return Array.prototype[fn].apply(this.nodes, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
Meta.prototype.each = Meta.prototype.forEach;
|
||||
|
||||
Meta.prototype.getAffectedAccounts = function(from) {
|
||||
if (this._affectedAccounts) {
|
||||
@@ -176,12 +143,16 @@ Meta.prototype.getAffectedAccounts = function(from) {
|
||||
// TransactionMetaSet::getAffectedAccounts
|
||||
for (var i=0; i<this.nodes.length; i++) {
|
||||
var node = this.nodes[i];
|
||||
var fields = (node.nodeType === 'CreatedNode') ? node.fieldsNew : node.fieldsFinal;
|
||||
var fields = (node.nodeType === 'CreatedNode')
|
||||
? node.fieldsNew
|
||||
: node.fieldsFinal;
|
||||
|
||||
for (var fieldName in fields) {
|
||||
var field = fields[fieldName];
|
||||
if (typeof field === 'string' && UInt160.is_valid(field)) {
|
||||
|
||||
if (this.isAccountField(fieldName) && UInt160.is_valid(field)) {
|
||||
accounts.push(field);
|
||||
} else if (~Meta.amountFieldsAffectingIssuer.indexOf(fieldName)) {
|
||||
} else if (~Meta.AMOUNT_FIELDS_AFFECTING_ISSUER.indexOf(fieldName)) {
|
||||
var amount = Amount.from_json(field);
|
||||
var issuer = amount.issuer();
|
||||
if (issuer.is_valid() && !issuer.is_zero()) {
|
||||
@@ -238,4 +209,53 @@ Meta.prototype.getAffectedBooks = function() {
|
||||
return this._affectedBooks;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Execute a function on each affected node.
|
||||
*
|
||||
* The callback is passed two parameters. The first is a node object which looks
|
||||
* like this:
|
||||
*
|
||||
* {
|
||||
* // Type of diff, e.g. CreatedNode, ModifiedNode
|
||||
* nodeType: 'CreatedNode'
|
||||
*
|
||||
* // Type of node affected, e.g. RippleState, AccountRoot
|
||||
* entryType: 'RippleState',
|
||||
*
|
||||
* // Index of the ledger this change occurred in
|
||||
* ledgerIndex: '01AB01AB...',
|
||||
*
|
||||
* // Contains all fields with later versions taking precedence
|
||||
* //
|
||||
* // This is a shorthand for doing things like checking which account
|
||||
* // this affected without having to check the nodeType.
|
||||
* fields: {...},
|
||||
*
|
||||
* // Old fields (before the change)
|
||||
* fieldsPrev: {...},
|
||||
*
|
||||
* // New fields (that have been added)
|
||||
* fieldsNew: {...},
|
||||
*
|
||||
* // Changed fields
|
||||
* fieldsFinal: {...}
|
||||
* }
|
||||
*/
|
||||
|
||||
[
|
||||
'forEach',
|
||||
'map',
|
||||
'filter',
|
||||
'every',
|
||||
'some',
|
||||
'reduce'
|
||||
].forEach(function(fn) {
|
||||
Meta.prototype[fn] = function() {
|
||||
return Array.prototype[fn].apply(this.nodes, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
Meta.prototype.each = Meta.prototype.forEach;
|
||||
|
||||
exports.Meta = Meta;
|
||||
|
||||
@@ -43,8 +43,9 @@ function OrderBook(remote, getsC, getsI, paysC, paysI, key) {
|
||||
this._shouldSubscribe = true;
|
||||
this._listeners = 0;
|
||||
this._offers = [ ];
|
||||
this._ownerFunds = { };
|
||||
this._offerCounts = { };
|
||||
this._ownerFunds = { };
|
||||
this._ownerOffers = { };
|
||||
|
||||
// We consider ourselves synchronized if we have a current
|
||||
// copy of the offers, we are online and subscribed to updates.
|
||||
@@ -180,6 +181,7 @@ OrderBook.prototype.unsubscribe = function() {
|
||||
|
||||
OrderBook.prototype.resetCache = function() {
|
||||
this._ownerFunds = { };
|
||||
this._ownerOffers = { };
|
||||
this._offerCounts = { };
|
||||
this._synchronized = false;
|
||||
};
|
||||
@@ -232,6 +234,8 @@ OrderBook.prototype.removeCachedFunds = function(account) {
|
||||
|
||||
/**
|
||||
* Get offer count for offer owner
|
||||
*
|
||||
* @param {String} account address
|
||||
*/
|
||||
|
||||
OrderBook.prototype.getOfferCount = function(account) {
|
||||
@@ -241,6 +245,8 @@ OrderBook.prototype.getOfferCount = function(account) {
|
||||
|
||||
/**
|
||||
* Increment offer count for offer owner
|
||||
*
|
||||
* @param {String} account address
|
||||
*/
|
||||
|
||||
OrderBook.prototype.incrementOfferCount = function(account) {
|
||||
@@ -252,6 +258,8 @@ OrderBook.prototype.incrementOfferCount = function(account) {
|
||||
|
||||
/**
|
||||
* Decrement offer count for offer owner
|
||||
*
|
||||
* @param {String} account address
|
||||
*/
|
||||
|
||||
OrderBook.prototype.decrementOfferCount = function(account) {
|
||||
@@ -261,6 +269,58 @@ OrderBook.prototype.decrementOfferCount = function(account) {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add offer amount to sum amount being offered by an account
|
||||
*
|
||||
* @param {String} account address
|
||||
* @param {Object|String} offer amount
|
||||
* @return sum
|
||||
*/
|
||||
|
||||
OrderBook.prototype.addOwnerOffer = function(account, amount) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
var previousAmount = this.getOwnerOfferSum(account);
|
||||
var newAmount = previousAmount.add(Amount.from_json(amount));
|
||||
this._ownerOffers[account] = newAmount;
|
||||
return newAmount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Subtract offer amount from sum amount being offered by an account
|
||||
*
|
||||
* @param {String} account address
|
||||
* @param {Object|String} offer amount
|
||||
* @return sum
|
||||
*/
|
||||
|
||||
OrderBook.prototype.subtractOwnerOffer = function(account, amount) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
var previousAmount = this.getOwnerOfferSum(account);
|
||||
var newAmount = previousAmount.subtract(Amount.from_json(amount));
|
||||
this._ownerOffers[account] = newAmount;
|
||||
return newAmount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get sum amount for offers by an account
|
||||
*
|
||||
* @param {String} account address
|
||||
* @return sum
|
||||
*/
|
||||
|
||||
OrderBook.prototype.getOwnerOfferSum = function(account) {
|
||||
assert(UInt160.is_valid(account), 'Account is invalid');
|
||||
var amount = this._ownerOffers[account];
|
||||
if (!amount) {
|
||||
if (this._currencyGets.is_native()) {
|
||||
amount = Amount.from_json('0');
|
||||
} else {
|
||||
amount = Amount.from_json('0' + OrderBook.IOU_SUFFIX);
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute funded amount for a balance/transferRate
|
||||
*
|
||||
@@ -358,11 +418,20 @@ OrderBook.prototype.setFundedAmount = function(offer, fundedAmount) {
|
||||
return offer;
|
||||
}
|
||||
|
||||
// Sum of offer amounts by an account
|
||||
var offerSum = this.getOwnerOfferSum(offer.Account);
|
||||
|
||||
if (offerSum.is_zero()) {
|
||||
// If there are no cached offer amounts for the account, default to
|
||||
// TakerGets of this offer
|
||||
offerSum = Amount.from_json(offer.TakerGets);
|
||||
}
|
||||
|
||||
offer.is_fully_funded = Amount.from_json(
|
||||
this._currencyGets.is_native()
|
||||
? fundedAmount
|
||||
: fundedAmount + OrderBook.IOU_SUFFIX
|
||||
).compareTo(Amount.from_json(offer.TakerGets)) >= 0;
|
||||
).compareTo(offerSum) >= 0;
|
||||
|
||||
if (offer.is_fully_funded) {
|
||||
offer.taker_gets_funded = Amount.from_json(offer.TakerGets).to_text();
|
||||
@@ -376,12 +445,8 @@ OrderBook.prototype.setFundedAmount = function(offer, fundedAmount) {
|
||||
? offer.TakerPays.value
|
||||
: offer.TakerPays;
|
||||
|
||||
var takerGetsValue = (typeof offer.TakerGets === 'object')
|
||||
? offer.TakerGets.value
|
||||
: offer.TakerGets;
|
||||
|
||||
var takerPays = Amount.from_json(takerPaysValue + OrderBook.IOU_SUFFIX);
|
||||
var takerGets = Amount.from_json(takerGetsValue + OrderBook.IOU_SUFFIX);
|
||||
var takerGets = Amount.from_json(offerSum);
|
||||
var fundedPays = Amount.from_json(fundedAmount + OrderBook.IOU_SUFFIX);
|
||||
var rate = takerPays.divide(takerGets);
|
||||
|
||||
@@ -662,9 +727,16 @@ OrderBook.offerRewrite = function(offer) {
|
||||
OrderBook.prototype.setOffers = function(offers) {
|
||||
assert(Array.isArray(offers));
|
||||
|
||||
var l = offers.length;
|
||||
var newOffers = [ ];
|
||||
|
||||
for (var i=0, l=offers.length; i<l; i++) {
|
||||
for (var i=0; i<l; i++) {
|
||||
var offer = offers[i];
|
||||
// Add offer amount to sum for account
|
||||
this.addOwnerOffer(offer.Account, offer.TakerGets);
|
||||
}
|
||||
|
||||
for (var i=0; i<l; i++) {
|
||||
var offer = OrderBook.offerRewrite(offers[i]);
|
||||
var fundedAmount;
|
||||
|
||||
@@ -675,8 +747,8 @@ OrderBook.prototype.setOffers = function(offers) {
|
||||
this.addCachedFunds(offer.Account, fundedAmount);
|
||||
}
|
||||
|
||||
this.setFundedAmount(offer, fundedAmount);
|
||||
this.incrementOfferCount(offer.Account);
|
||||
this.setFundedAmount(offer, fundedAmount);
|
||||
|
||||
newOffers.push(offer);
|
||||
}
|
||||
@@ -888,6 +960,9 @@ OrderBook.prototype.insertOffer = function(node, fundedAmount) {
|
||||
log.info('inserting offer', this._key, node.fields);
|
||||
}
|
||||
|
||||
// Add offer amount to sum for account
|
||||
this.addOwnerOffer(node.fields.Account, node.fields.TakerGets);
|
||||
|
||||
var nodeFields = OrderBook.offerRewrite(node.fields);
|
||||
nodeFields.LedgerEntryType = node.entryType;
|
||||
nodeFields.index = node.ledgerIndex;
|
||||
@@ -904,7 +979,7 @@ OrderBook.prototype.insertOffer = function(node, fundedAmount) {
|
||||
// XXX Should use Amount#from_quality
|
||||
var price = Amount.from_json(
|
||||
nodeFields.TakerPays
|
||||
).ratio_human(node.fields.TakerGets, DATE_REF);
|
||||
).ratio_human(nodeFields.TakerGets, DATE_REF);
|
||||
|
||||
for (var i=0, l=this._offers.length; i<l; i++) {
|
||||
var offer = this._offers[i];
|
||||
@@ -944,14 +1019,21 @@ OrderBook.prototype.modifyOffer = function(node, isDeletedNode) {
|
||||
var offer = this._offers[i];
|
||||
if (offer.index === node.ledgerIndex) {
|
||||
if (isDeletedNode) {
|
||||
// Multiple offers same account?
|
||||
// Remove offer amount from sum for account
|
||||
this.subtractOwnerOffer(offer.Account, offer.TakerGets);
|
||||
this._offers.splice(i, 1);
|
||||
this.emit('offer_removed', offer);
|
||||
} else {
|
||||
// TODO: This assumes no fields are deleted, which is
|
||||
// probably a safe assumption, but should be checked.
|
||||
var previousOffer = extend({}, offer);
|
||||
var previousOffer = extend({ }, offer);
|
||||
extend(offer, node.fieldsFinal);
|
||||
|
||||
// Remove offer amount from sum for account
|
||||
this.subtractOwnerOffer(offer.Account, previousOffer.TakerGets);
|
||||
// Add offer amount from sum for account
|
||||
this.addOwnerOffer(offer.Account, offer.TakerGets);
|
||||
|
||||
this.emit('offer_changed', previousOffer, offer);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -35,28 +35,27 @@ util.inherits(PathFind, EventEmitter);
|
||||
PathFind.prototype.create = function () {
|
||||
var self = this;
|
||||
|
||||
var req = this.remote.request_path_find_create(this.src_account,
|
||||
this.dst_account,
|
||||
this.dst_amount,
|
||||
this.src_currencies,
|
||||
handleInitialPath);
|
||||
var req = this.remote.request_path_find_create(
|
||||
this.src_account,
|
||||
this.dst_account,
|
||||
this.dst_amount,
|
||||
this.src_currencies);
|
||||
|
||||
function handleInitialPath(err, msg) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
} else {
|
||||
self.notify_update(msg);
|
||||
}
|
||||
}
|
||||
req.once('error', function(err) {
|
||||
self.emit('error', err);
|
||||
});
|
||||
req.once('success', function(msg) {
|
||||
self.notify_update(msg);
|
||||
});
|
||||
|
||||
// XXX We should add ourselves to prepare_subscribe or a similar mechanism so
|
||||
// that we can resubscribe after a reconnection.
|
||||
|
||||
req.request();
|
||||
req.broadcast().request();
|
||||
};
|
||||
|
||||
PathFind.prototype.close = function () {
|
||||
this.remote.request_path_find_close().request();
|
||||
this.remote.request_path_find_close().broadcast().request();
|
||||
this.emit('end');
|
||||
this.emit('close');
|
||||
};
|
||||
|
||||
67
src/js/ripple/rangeset.js
Normal file
67
src/js/ripple/rangeset.js
Normal file
@@ -0,0 +1,67 @@
|
||||
var assert = require('assert');
|
||||
var lodash = require('lodash');
|
||||
|
||||
function RangeSet() {
|
||||
this._ranges = [ ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a ledger range
|
||||
*
|
||||
* @param {Number|String} range string (n-n2,n3-n4)
|
||||
*/
|
||||
|
||||
RangeSet.prototype.add = function(range) {
|
||||
assert(typeof range !== 'number' || !isNaN(range), 'Ledger range malformed');
|
||||
|
||||
range = String(range).split(',');
|
||||
|
||||
if (range.length > 1) {
|
||||
return range.forEach(this.add, this);
|
||||
}
|
||||
|
||||
range = range[0].split('-').map(Number);
|
||||
|
||||
var lRange = {
|
||||
start: range[0],
|
||||
end: range[range.length === 1 ? 0 : 1]
|
||||
};
|
||||
|
||||
// Comparisons on NaN should be falsy
|
||||
assert(lRange.start <= lRange.end, 'Ledger range malformed');
|
||||
|
||||
var insertionPoint = lodash.sortedIndex(this._ranges, lRange, function(r) {
|
||||
return r.start;
|
||||
});
|
||||
|
||||
this._ranges.splice(insertionPoint, 0, lRange);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Check presence of ledger in range
|
||||
*
|
||||
* @param {Number|String} ledger
|
||||
* @return Boolean
|
||||
*/
|
||||
|
||||
RangeSet.prototype.has =
|
||||
RangeSet.prototype.contains = function(ledger) {
|
||||
assert(ledger != null && !isNaN(ledger), 'Ledger must be a number');
|
||||
|
||||
ledger = Number(ledger);
|
||||
|
||||
return this._ranges.some(function(r) {
|
||||
return ledger >= r.start && ledger <= r.end;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset ledger ranges
|
||||
*/
|
||||
|
||||
RangeSet.prototype.reset = function() {
|
||||
this._ranges = [ ];
|
||||
};
|
||||
|
||||
exports.RangeSet = RangeSet;
|
||||
@@ -17,6 +17,7 @@ var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var assert = require('assert');
|
||||
var LRU = require('lru-cache');
|
||||
var async = require('async');
|
||||
var Server = require('./server').Server;
|
||||
var Request = require('./request').Request;
|
||||
var Server = require('./server').Server;
|
||||
@@ -33,6 +34,7 @@ var SerializedObject = require('./serializedobject').SerializedObject;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
var utils = require('./utils');
|
||||
var sjcl = require('./utils').sjcl;
|
||||
var hashprefixes = require('./hashprefixes');
|
||||
var config = require('./config');
|
||||
var log = require('./log').internal.sub('remote');
|
||||
|
||||
@@ -325,6 +327,7 @@ Remote.from_config = function(obj, trace) {
|
||||
* Check that server message is valid
|
||||
*
|
||||
* @param {Object} message
|
||||
* @return Boolean
|
||||
*/
|
||||
|
||||
Remote.isValidMessage = function(message) {
|
||||
@@ -337,6 +340,7 @@ Remote.isValidMessage = function(message) {
|
||||
* ledger data
|
||||
*
|
||||
* @param {Object} message
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
Remote.isValidLedgerData = function(message) {
|
||||
@@ -355,6 +359,7 @@ Remote.isValidLedgerData = function(message) {
|
||||
* load status data
|
||||
*
|
||||
* @param {Object} message
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
Remote.isValidLoadStatus = function(message) {
|
||||
@@ -362,6 +367,18 @@ Remote.isValidLoadStatus = function(message) {
|
||||
&& (typeof message.load_factor === 'number');
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that provided ledger is validated
|
||||
*
|
||||
* @param {Object} ledger
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
Remote.isValidated = function(message) {
|
||||
return (message && typeof message === 'object')
|
||||
&& (message.validated === true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the emitted state: 'online' or 'offline'
|
||||
*
|
||||
@@ -1020,6 +1037,52 @@ Remote.prototype.requestLedgerCurrent = function(callback) {
|
||||
return new Request(this, 'ledger_current').callback(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Request ledger_data
|
||||
*
|
||||
* Get the contents of a specified ledger
|
||||
*
|
||||
* @param {Object} options
|
||||
* @property {Boolean} [options.binary] - Flag which determines if rippled returns binary or parsed JSON
|
||||
* @property {String|Number} [options.ledger] - Hash or sequence of a ledger to get contents for
|
||||
* @property {Number} [options.limit] - Number of contents to retrieve from the ledger
|
||||
* @property {Function} callback
|
||||
*
|
||||
* @callback
|
||||
* @param {Error} error
|
||||
* @param {LedgerData} ledgerData
|
||||
*
|
||||
* @return {Request} request
|
||||
*/
|
||||
|
||||
Remote.prototype.requestLedgerData = function(options, callback) {
|
||||
var request = new Request(this, 'ledger_data');
|
||||
|
||||
request.message.binary = options.binary !== false;
|
||||
request.selectLedger(options.ledger);
|
||||
request.message.limit = options.limit;
|
||||
|
||||
request.once('success', function(res) {
|
||||
if (options.binary === false) {
|
||||
request.emit('state', res);
|
||||
return;
|
||||
}
|
||||
|
||||
async.mapSeries(res.state, function(ledgerData, next) {
|
||||
async.setImmediate(function() {
|
||||
next(null, Remote.parseBinaryLedgerData(ledgerData));
|
||||
});
|
||||
}, function(err, state) {
|
||||
res.state = state;
|
||||
request.emit('state', res);
|
||||
});
|
||||
});
|
||||
|
||||
request.callback(callback, 'state');
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request ledger_entry
|
||||
*
|
||||
@@ -1184,17 +1247,40 @@ Remote.prototype.requestTransactionEntry = function(hash, ledgerHash, callback)
|
||||
/**
|
||||
* Request tx
|
||||
*
|
||||
* @param {String} transaction hash
|
||||
* @param {Object|String} hash
|
||||
* @property {String} hash.hash - Transaction hash
|
||||
* @property {Boolean} [hash.binary=true] - Flag which determines if rippled returns binary or parsed JSON
|
||||
* @param [Function] callback
|
||||
* @return {Request} request
|
||||
*/
|
||||
|
||||
Remote.prototype.requestTransaction =
|
||||
Remote.prototype.requestTx = function(hash, callback) {
|
||||
var options;
|
||||
|
||||
if (typeof hash === 'string') {
|
||||
options = {
|
||||
hash: hash
|
||||
}
|
||||
} else {
|
||||
options = hash;
|
||||
}
|
||||
|
||||
var request = new Request(this, 'tx');
|
||||
|
||||
request.message.transaction = hash;
|
||||
request.callback(callback);
|
||||
request.message.binary = options.binary !== false;
|
||||
request.message.transaction = options.hash;
|
||||
|
||||
request.once('success', function(res) {
|
||||
if (options.binary === false) {
|
||||
request.emit('transaction', res);
|
||||
return;
|
||||
}
|
||||
|
||||
request.emit('transaction', Remote.parseBinaryTransaction(res));
|
||||
});
|
||||
|
||||
request.callback(callback, 'transaction');
|
||||
|
||||
return request;
|
||||
};
|
||||
@@ -1258,7 +1344,7 @@ Remote.accountRequest = function(type, options, callback) {
|
||||
request.message.peer = UInt160.json_rewrite(peer);
|
||||
}
|
||||
|
||||
if (!isNaN(Number(limit))) {
|
||||
if (!isNaN(limit)) {
|
||||
limit = Number(limit);
|
||||
|
||||
// max for 32-bit unsigned int is 4294967295
|
||||
@@ -1370,16 +1456,15 @@ Remote.prototype.requestAccountOffers = function(options, callback) {
|
||||
* Request account_tx
|
||||
*
|
||||
* @param {Object} options
|
||||
*
|
||||
* @param {String} account
|
||||
* @param [Number] ledger_index_min defaults to -1 if ledger_index_max is specified.
|
||||
* @param [Number] ledger_index_max defaults to -1 if ledger_index_min is specified.
|
||||
* @param [Boolean] binary, defaults to false
|
||||
* @param [Boolean] parseBinary, defaults to true
|
||||
* @param [Boolean] count, defaults to false
|
||||
* @param [Boolean] descending, defaults to false
|
||||
* @param [Number] offset, defaults to 0
|
||||
* @param [Number] limit
|
||||
* @property {String} options.account
|
||||
* @property {Number} options.ledger_index_min - Defaults to -1 if ledger_index_max is specified.
|
||||
* @property {Number} options.ledger_index_max - Defaults to -1 if ledger_index_min is specified.
|
||||
* @property {Boolean} options.binary - Defaults to true
|
||||
* @property {Boolean} options.parseBinary - Defaults to true
|
||||
* @property {Boolean} options.count - Defaults to false
|
||||
* @property {Boolean} options.descending - Defaults to false
|
||||
* @property {Number} options.offset - Defaults to 0
|
||||
* @property {Number} options.limit
|
||||
*
|
||||
* @param [Function] callback
|
||||
* @return {Request}
|
||||
@@ -1392,6 +1477,8 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
||||
|
||||
var request = new Request(this, 'account_tx');
|
||||
|
||||
options.binary = options.binary !== false;
|
||||
|
||||
if (options.min_ledger !== void(0)) {
|
||||
options.ledger_index_min = options.min_ledger;
|
||||
}
|
||||
@@ -1424,10 +1511,19 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
||||
}, options);
|
||||
|
||||
request.once('success', function(res) {
|
||||
if (options.parseBinary) {
|
||||
res.transactions = res.transactions.map(Remote.parseBinaryTransaction);
|
||||
if (!options.parseBinary) {
|
||||
request.emit('transactions', res);
|
||||
return;
|
||||
}
|
||||
request.emit('transactions', res);
|
||||
|
||||
async.mapSeries(res.transactions, function(transaction, next) {
|
||||
async.setImmediate(function() {
|
||||
next(null, Remote.parseBinaryAccountTransaction(transaction));
|
||||
});
|
||||
}, function(err, transactions) {
|
||||
res.transactions = transactions;
|
||||
request.emit('transactions', res);
|
||||
});
|
||||
});
|
||||
|
||||
request.callback(callback, 'transactions');
|
||||
@@ -1440,13 +1536,69 @@ Remote.prototype.requestAccountTx = function(options, callback) {
|
||||
* @return {Transaction}
|
||||
*/
|
||||
|
||||
Remote.parseBinaryAccountTransaction = function(transaction) {
|
||||
var tx_obj = new SerializedObject(transaction.tx_blob);
|
||||
var tx_obj_json = tx_obj.to_json();
|
||||
var meta = new SerializedObject(transaction.meta).to_json();
|
||||
|
||||
var tx_result = {
|
||||
validated: transaction.validated
|
||||
};
|
||||
|
||||
tx_result.meta = meta;
|
||||
tx_result.tx = tx_obj_json;
|
||||
tx_result.tx.hash = tx_obj.hash(hashprefixes.HASH_TX_ID).to_hex();
|
||||
tx_result.tx.ledger_index = transaction.ledger_index;
|
||||
tx_result.tx.inLedger = transaction.ledger_index;
|
||||
|
||||
if (typeof meta.DeliveredAmount === 'object') {
|
||||
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
||||
} else if (typeof tx_obj_json.Amount === 'string' || typeof tx_obj_json.Amount === 'object') {
|
||||
tx_result.meta.delivered_amount = tx_obj_json.Amount;
|
||||
}
|
||||
|
||||
return tx_result;
|
||||
};
|
||||
|
||||
Remote.parseBinaryTransaction = function(transaction) {
|
||||
var tx = { validated: transaction.validated };
|
||||
tx.meta = new SerializedObject(transaction.meta).to_json();
|
||||
tx.tx = new SerializedObject(transaction.tx_blob).to_json();
|
||||
tx.tx.ledger_index = transaction.ledger_index;
|
||||
tx.tx.hash = Transaction.from_json(tx.tx).hash();
|
||||
return tx;
|
||||
var tx_obj = new SerializedObject(transaction.tx).to_json();
|
||||
var meta = new SerializedObject(transaction.meta).to_json();
|
||||
|
||||
var tx_result = tx_obj;
|
||||
|
||||
tx_result.date = transaction.date;
|
||||
tx_result.hash = transaction.hash;
|
||||
tx_result.inLedger = transaction.inLedger;
|
||||
tx_result.ledger_index = transaction.ledger_index;
|
||||
tx_result.meta = meta;
|
||||
tx_result.validated = transaction.validated;
|
||||
|
||||
if (typeof meta.DeliveredAmount === 'string' || typeof meta.DeliveredAmount === 'object') {
|
||||
tx_result.meta.delivered_amount = meta.DeliveredAmount;
|
||||
} else if (typeof tx_obj.Amount === 'string' || typeof tx_obj.Amount === 'object') {
|
||||
tx_result.meta.delivered_amount = tx_obj.Amount;
|
||||
}
|
||||
|
||||
return tx_result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse binary ledger state data
|
||||
*
|
||||
* @param {Object} ledgerData
|
||||
* @property {String} ledgerData.data
|
||||
* @property {String} ledgerData.index
|
||||
*
|
||||
* @return {State}
|
||||
*/
|
||||
|
||||
Remote.parseBinaryLedgerData = function(ledgerData) {
|
||||
var data = new SerializedObject(ledgerData.data);
|
||||
|
||||
var state = data.to_json();
|
||||
state.index = ledgerData.index;
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1476,14 +1628,19 @@ Remote.prototype.requestTxHistory = function(start, callback) {
|
||||
/**
|
||||
* Request book_offers
|
||||
*
|
||||
* @param {Object} gets
|
||||
* @param {Object} pays
|
||||
* @param {String} taker
|
||||
* @param [Function] calback
|
||||
* @param {Object} options
|
||||
* @param {Object} options.gets - taker_gets with issuer and currency
|
||||
* @param {Object} options.pays - taker_pays with issuer and currency
|
||||
* @param {String} [options.taker]
|
||||
* @param {String} [options.ledger]
|
||||
* @param {String|Number} [options.limit]
|
||||
* @param [Function] callback
|
||||
* @return {Request}
|
||||
*/
|
||||
|
||||
Remote.prototype.requestBookOffers = function(gets, pays, taker, callback) {
|
||||
var ledger;
|
||||
var limit;
|
||||
var lastArg = arguments[arguments.length - 1];
|
||||
|
||||
if (gets.hasOwnProperty('gets') || gets.hasOwnProperty('taker_gets')) {
|
||||
@@ -1495,6 +1652,8 @@ Remote.prototype.requestBookOffers = function(gets, pays, taker, callback) {
|
||||
taker = options.taker;
|
||||
pays = options.pays || options.taker_pays;
|
||||
gets = options.gets || options.taker_gets;
|
||||
ledger = options.ledger;
|
||||
limit = options.limit;
|
||||
}
|
||||
|
||||
if (typeof lastArg === 'function') {
|
||||
@@ -1520,9 +1679,26 @@ Remote.prototype.requestBookOffers = function(gets, pays, taker, callback) {
|
||||
}
|
||||
|
||||
request.message.taker = taker ? taker : UInt160.ACCOUNT_ONE;
|
||||
request.ledgerSelect(ledger);
|
||||
|
||||
if (!isNaN(limit)) {
|
||||
limit = Number(limit);
|
||||
|
||||
// max for 32-bit unsigned int is 4294967295
|
||||
// we'll clamp to 1e9
|
||||
if (limit > 1e9) {
|
||||
limit = 1e9;
|
||||
}
|
||||
// min for 32-bit unsigned int is 0
|
||||
// we'll clamp to 0
|
||||
if (limit < 0) {
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
request.message.limit = limit;
|
||||
}
|
||||
|
||||
request.callback(callback);
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
@@ -1983,6 +2159,44 @@ Remote.prototype.dirtyAccountRoot = function(account) {
|
||||
delete this.ledgers.current.account_root[account];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an Offer from the ledger
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {String|Number} options.ledger
|
||||
* @param {String} [options.account] - Required unless using options.index
|
||||
* @param {Number} [options.sequence] - Required unless using options.index
|
||||
* @param {String} [options.index] - Required only if options.account and options.sequence not provided
|
||||
*
|
||||
* @callback
|
||||
* @param {Error} error
|
||||
* @param {Object} message
|
||||
*
|
||||
* @return {Request}
|
||||
*/
|
||||
|
||||
Remote.prototype.requestOffer = function(options, callback) {
|
||||
|
||||
var request = this.requestLedgerEntry('offer');
|
||||
|
||||
if (options.account && options.sequence) {
|
||||
request.offerId(options.account, options.sequence);
|
||||
} else if (options.index) {
|
||||
request.offerIndex(options.index);
|
||||
}
|
||||
|
||||
request.ledgerSelect(options.ledger);
|
||||
|
||||
request.once('success', function(res) {
|
||||
request.emit('offer',res);
|
||||
});
|
||||
|
||||
request.callback(callback, 'offer');
|
||||
|
||||
return request;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get an account's balance
|
||||
*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var async = require('async');
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
@@ -24,6 +25,9 @@ function Request(remote, command) {
|
||||
|
||||
this.remote = remote;
|
||||
this.requested = false;
|
||||
this.reconnectTimeout = 1000 * 3;
|
||||
this.successEvent = 'success';
|
||||
this.errorEvent = 'error';
|
||||
this.message = {
|
||||
command: command,
|
||||
id: void(0)
|
||||
@@ -32,22 +36,20 @@ function Request(remote, command) {
|
||||
|
||||
util.inherits(Request, EventEmitter);
|
||||
|
||||
Request.prototype.broadcast = function() {
|
||||
var connectedServers = this.remote.getConnectedServers();
|
||||
this.request(connectedServers);
|
||||
return connectedServers.length;
|
||||
};
|
||||
|
||||
// Send the request to a remote.
|
||||
Request.prototype.request = function(servers, callback) {
|
||||
if (this.requested) {
|
||||
return this;
|
||||
}
|
||||
this.emit('before');
|
||||
|
||||
if (typeof servers === 'function') {
|
||||
callback = servers;
|
||||
}
|
||||
|
||||
this.callback(callback);
|
||||
|
||||
if (this.requested) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.requested = true;
|
||||
this.on('error', function(){});
|
||||
this.emit('request', this.remote);
|
||||
@@ -61,7 +63,129 @@ Request.prototype.request = function(servers, callback) {
|
||||
this.remote.request(this);
|
||||
}
|
||||
|
||||
this.callback(callback);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Broadcast request to all servers, filter responses if a function is
|
||||
* provided. Return first response that satisfies the filter. Pre-filter
|
||||
* requests by ledger_index (if a ledger_index is set on the request), and
|
||||
* automatically retry servers when they reconnect--if they are expected to
|
||||
*
|
||||
* Whew
|
||||
*
|
||||
* @param [Function] fn
|
||||
*/
|
||||
|
||||
Request.prototype.filter =
|
||||
Request.prototype.addFilter =
|
||||
Request.prototype.broadcast = function(filterFn) {
|
||||
var self = this;
|
||||
|
||||
if (!this.requested) {
|
||||
// Defer until requested, and prevent the normal request() from executing
|
||||
this.once('before', function() {
|
||||
self.requested = true;
|
||||
self.broadcast(filterFn);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
var filterFn = typeof filterFn === 'function' ? filterFn : Boolean;
|
||||
var lastResponse = new Error('No servers available');
|
||||
var connectTimeouts = { };
|
||||
var emit = this.emit;
|
||||
|
||||
this.emit = function(event, a, b) {
|
||||
// Proxy success/error events
|
||||
switch (event) {
|
||||
case 'success':
|
||||
case 'error':
|
||||
emit.call(self, 'proposed', a, b);
|
||||
break;
|
||||
default:
|
||||
emit.apply(self, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
function iterator(server, callback) {
|
||||
// Iterator is called in parallel
|
||||
|
||||
if (server.isConnected()) {
|
||||
// Listen for proxied success/error event and apply filter
|
||||
self.once('proposed', function(res) {
|
||||
lastResponse = res;
|
||||
callback(filterFn(res));
|
||||
});
|
||||
|
||||
return server._request(self);
|
||||
}
|
||||
|
||||
// Server is disconnected but should reconnect. Wait for it to reconnect,
|
||||
// and abort after a timeout
|
||||
var serverID = server.getServerID();
|
||||
|
||||
function serverReconnected() {
|
||||
clearTimeout(connectTimeouts[serverID]);
|
||||
connectTimeouts[serverID] = null;
|
||||
iterator(server, callback);
|
||||
};
|
||||
|
||||
connectTimeouts[serverID] = setTimeout(function() {
|
||||
server.removeListener('connect', serverReconnected);
|
||||
callback(false);
|
||||
}, self.reconnectTimeout);
|
||||
|
||||
server.once('connect', serverReconnected);
|
||||
};
|
||||
|
||||
function complete(success) {
|
||||
// Emit success if the filter is satisfied by any server
|
||||
// Emit error if the filter is not satisfied by any server
|
||||
// Include the last response
|
||||
emit.call(self, success ? 'success' : 'error', lastResponse);
|
||||
};
|
||||
|
||||
var servers = this.remote._servers.filter(function(server) {
|
||||
// Pre-filter servers that are disconnected and should not reconnect
|
||||
return (server.isConnected() || server._shouldConnect)
|
||||
// Pre-filter servers that do not contain the ledger in request
|
||||
&& (!self.message.hasOwnProperty('ledger_index')
|
||||
|| server.hasLedger(self.message.ledger_index))
|
||||
&& (!self.message.hasOwnProperty('ledger_index_min')
|
||||
|| self.message.ledger_index_min === -1
|
||||
|| server.hasLedger(self.message.ledger_index_min))
|
||||
&& (!self.message.hasOwnProperty('ledger_index_max')
|
||||
|| self.message.ledger_index_max === -1
|
||||
|| server.hasLedger(self.message.ledger_index_max))
|
||||
});
|
||||
|
||||
// Apply iterator in parallel to connected servers, complete when the
|
||||
// supplied filter function is satisfied once by a server's response
|
||||
async.some(servers, iterator, complete);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.cancel = function() {
|
||||
this.removeAllListeners();
|
||||
this.on('error', function(){});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.setCallback = function(fn) {
|
||||
if (typeof fn === 'function') {
|
||||
this.callback(fn);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.setReconnectTimeout = function(timeout) {
|
||||
if (typeof timeout === 'number' && !isNaN(timeout)) {
|
||||
this.reconnectTimeout = timeout;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -73,6 +197,13 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (typeof successEvent === 'string') {
|
||||
this.successEvent = successEvent;
|
||||
}
|
||||
if (typeof errorEvent === 'string') {
|
||||
this.errorEvent = errorEvent;
|
||||
}
|
||||
|
||||
var called = false;
|
||||
|
||||
function requestSuccess(message) {
|
||||
@@ -94,8 +225,8 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
||||
}
|
||||
};
|
||||
|
||||
this.once(successEvent || 'success', requestSuccess);
|
||||
this.once(errorEvent || 'error' , requestError);
|
||||
this.once(this.successEvent, requestSuccess);
|
||||
this.once(this.errorEvent, requestError);
|
||||
this.request();
|
||||
|
||||
return this;
|
||||
@@ -124,6 +255,7 @@ Request.prototype.timeout = function(duration, callback) {
|
||||
}
|
||||
|
||||
emit.call(self, 'timeout');
|
||||
self.cancel();
|
||||
}, duration);
|
||||
|
||||
this.emit = function() {
|
||||
@@ -222,11 +354,10 @@ Request.prototype.ledgerSelect = function(ledger) {
|
||||
case 'validated':
|
||||
this.message.ledger_index = ledger;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Number(ledger)) {
|
||||
if (Number(ledger) && isFinite(Number(ledger))) {
|
||||
this.message.ledger_index = Number(ledger);
|
||||
} else if (/^[A-F0-9]+$/.test(ledger)) {
|
||||
} else if (/^[A-F0-9]{64}$/.test(ledger)) {
|
||||
this.message.ledger_hash = ledger;
|
||||
}
|
||||
break;
|
||||
@@ -236,12 +367,12 @@ Request.prototype.ledgerSelect = function(ledger) {
|
||||
};
|
||||
|
||||
Request.prototype.accountRoot = function(account) {
|
||||
this.message.account_root = UInt160.json_rewrite(account);
|
||||
this.message.account_root = UInt160.json_rewrite(account);
|
||||
return this;
|
||||
};
|
||||
|
||||
Request.prototype.index = function(index) {
|
||||
this.message.index = index;
|
||||
this.message.index = index;
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -250,8 +381,8 @@ Request.prototype.index = function(index) {
|
||||
// --> seq : sequence number of transaction creating offer (integer)
|
||||
Request.prototype.offerId = function(account, sequence) {
|
||||
this.message.offer = {
|
||||
account: UInt160.json_rewrite(account),
|
||||
seq: sequence
|
||||
account: UInt160.json_rewrite(account),
|
||||
seq: sequence
|
||||
};
|
||||
return this;
|
||||
};
|
||||
@@ -286,8 +417,8 @@ Request.prototype.txBlob = function(json) {
|
||||
|
||||
Request.prototype.rippleState = function(account, issuer, currency) {
|
||||
this.message.ripple_state = {
|
||||
currency : currency,
|
||||
accounts : [
|
||||
currency: currency,
|
||||
accounts: [
|
||||
UInt160.json_rewrite(account),
|
||||
UInt160.json_rewrite(issuer)
|
||||
]
|
||||
@@ -322,12 +453,8 @@ Request.prototype.addAccount = function(account, proposed) {
|
||||
}
|
||||
|
||||
var processedAccount = UInt160.json_rewrite(account);
|
||||
|
||||
if (proposed === true) {
|
||||
this.message.accounts_proposed = (this.message.accounts_proposed || []).concat(processedAccount);
|
||||
} else {
|
||||
this.message.accounts = (this.message.accounts || []).concat(processedAccount);
|
||||
}
|
||||
var prop = proposed === true ? 'accounts_proposed' : 'accounts';
|
||||
this.message[prop] = (this.message[prop] || []).concat(processedAccount);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
var request = require('superagent');
|
||||
var Currency = require('./currency').Currency;
|
||||
|
||||
var RippleTxt = {
|
||||
txts : { }
|
||||
};
|
||||
|
||||
RippleTxt.urlTemplates = [
|
||||
'https://{{domain}}/ripple.txt',
|
||||
'https://www.{{domain}}/ripple.txt',
|
||||
'https://ripple.{{domain}}/ripple.txt',
|
||||
'http://{{domain}}/ripple.txt',
|
||||
'http://www.{{domain}}/ripple.txt',
|
||||
'http://ripple.{{domain}}/ripple.txt'
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets the ripple.txt file for the given domain
|
||||
* @param {string} domain - Domain to retrieve file from
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
RippleTxt.get = function(domain, fn) {
|
||||
var self = this;
|
||||
|
||||
if (self.txts[domain]) {
|
||||
return fn(null, self.txts[domain]);
|
||||
}
|
||||
|
||||
;(function nextUrl(i) {
|
||||
var url = RippleTxt.urlTemplates[i];
|
||||
|
||||
if (!url) {
|
||||
return fn(new Error('No ripple.txt found'));
|
||||
}
|
||||
|
||||
url = url.replace('{{domain}}', domain);
|
||||
|
||||
request.get(url, function(err, resp) {
|
||||
if (err || !resp.text) {
|
||||
return nextUrl(++i);
|
||||
}
|
||||
|
||||
var sections = self.parse(resp.text);
|
||||
self.txts[domain] = sections;
|
||||
|
||||
fn(null, sections);
|
||||
});
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a ripple.txt file
|
||||
* @param {string} txt - Unparsed ripple.txt data
|
||||
*/
|
||||
|
||||
RippleTxt.parse = function(txt) {
|
||||
var currentSection = '';
|
||||
var sections = { };
|
||||
|
||||
txt = txt.replace(/\r?\n/g, '\n').split('\n');
|
||||
|
||||
for (var i = 0, l = txt.length; i < l; i++) {
|
||||
var line = txt[i];
|
||||
|
||||
if (!line.length || line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0] === '[' && line[line.length - 1] === ']') {
|
||||
currentSection = line.slice(1, line.length - 1);
|
||||
sections[currentSection] = [];
|
||||
} else {
|
||||
line = line.replace(/^\s+|\s+$/g, '');
|
||||
if (sections[currentSection]) {
|
||||
sections[currentSection].push(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sections;
|
||||
};
|
||||
|
||||
/**
|
||||
* extractDomain
|
||||
* attempt to extract the domain from a given url
|
||||
* returns the url if unsuccessful
|
||||
* @param {Object} url
|
||||
*/
|
||||
|
||||
RippleTxt.extractDomain = function (url) {
|
||||
match = /[^.]*\.[^.]{2,3}(?:\.[^.]{2,3})?([^.\?][^\?.]+?)?$/.exec(url);
|
||||
return match && match[0] ? match[0] : url;
|
||||
};
|
||||
|
||||
/**
|
||||
* getCurrencies
|
||||
* returns domain, issuer account and currency object
|
||||
* for each currency found in the domain's ripple.txt file
|
||||
* @param {Object} domain
|
||||
* @param {Object} fn
|
||||
*/
|
||||
|
||||
RippleTxt.getCurrencies = function(domain, fn) {
|
||||
domain = RippleTxt.extractDomain(domain);
|
||||
this.get(domain, function(err, txt) {
|
||||
if (err) {
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
if (err || !txt.currencies || !txt.accounts) {
|
||||
return fn(null, []);
|
||||
}
|
||||
|
||||
//NOTE: this won't be accurate if there are
|
||||
//multiple issuer accounts with different
|
||||
//currencies associated with each.
|
||||
var issuer = txt.accounts[0];
|
||||
var currencies = [];
|
||||
|
||||
txt.currencies.forEach(function(currency) {
|
||||
currencies.push({
|
||||
issuer : issuer,
|
||||
currency : Currency.from_json(currency),
|
||||
domain : domain
|
||||
});
|
||||
});
|
||||
|
||||
fn(null, currencies);
|
||||
});
|
||||
};
|
||||
|
||||
exports.RippleTxt = RippleTxt;
|
||||
@@ -210,7 +210,7 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
|
||||
if (typeof structure.to_json === 'function') {
|
||||
output = structure.to_json();
|
||||
} else if (structure instanceof BigInteger) {
|
||||
output = structure.toString(16).toUpperCase();
|
||||
output = ('0000000000000000' + structure.toString(16).toUpperCase()).slice(-16);
|
||||
} else {
|
||||
//new Array or Object
|
||||
output = new structure.constructor();
|
||||
|
||||
@@ -234,6 +234,7 @@ var STInt64 = exports.Int64 = new SerializedType({
|
||||
// pessimistic numeric fraek. What doth lief?
|
||||
var result = new BigInteger([0].concat(bytes), 256);
|
||||
assert(result instanceof BigInteger);
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
@@ -541,6 +542,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
//It's an entry-begin tag.
|
||||
//console.log('It's an entry-begin tag.');
|
||||
var entry = {};
|
||||
var type = 0;
|
||||
|
||||
if (tag_byte & this.typeAccount) {
|
||||
//console.log('entry.account');
|
||||
@@ -548,6 +550,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
console.log('BTA:', bta);*/
|
||||
entry.account = STHash160.parse(so);
|
||||
entry.account.set_version(Base.VER_ACCOUNT_ID);
|
||||
type = type | this.typeAccount;
|
||||
}
|
||||
if (tag_byte & this.typeCurrency) {
|
||||
//console.log('entry.currency');
|
||||
@@ -555,6 +558,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
if (entry.currency.to_json() === 'XRP' && !entry.currency.is_native()) {
|
||||
entry.non_native = true;
|
||||
}
|
||||
type = type | this.typeCurrency;
|
||||
}
|
||||
if (tag_byte & this.typeIssuer) {
|
||||
//console.log('entry.issuer');
|
||||
@@ -562,9 +566,14 @@ var STPathSet = exports.PathSet = new SerializedType({
|
||||
// Enable and set correct type of base-58 encoding
|
||||
entry.issuer.set_version(Base.VER_ACCOUNT_ID);
|
||||
//console.log('DONE WITH ISSUER!');
|
||||
|
||||
type = type | this.typeIssuer;
|
||||
}
|
||||
|
||||
if (entry.account || entry.currency || entry.issuer) {
|
||||
entry.type = type;
|
||||
entry.type_hex = ("000000000000000" + type.toString(16)).slice(-16);
|
||||
|
||||
current_path.push(entry);
|
||||
} else {
|
||||
throw new Error('Invalid path entry'); //It must have at least something in it.
|
||||
@@ -674,7 +683,11 @@ var STMemo = exports.STMemo = new SerializedType({
|
||||
}
|
||||
|
||||
if (output['MemoType'] !== void(0)) {
|
||||
output['parsed_memo_type'] = convertHexToString(output['MemoType']);
|
||||
var parsedType = convertHexToString(output['MemoType']);
|
||||
|
||||
if (parsedType !== 'unformatted_memo') {
|
||||
output['parsed_memo_type'] = convertHexToString(output['MemoType']);
|
||||
}
|
||||
}
|
||||
|
||||
if (output['MemoFormat'] !== void(0)) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
var util = require('util');
|
||||
var url = require('url');
|
||||
var LRU = require('lru-cache');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var Amount = require('./amount').Amount;
|
||||
var RangeSet = require('./rangeset').RangeSet;
|
||||
var log = require('./log').internal.sub('server');
|
||||
|
||||
/**
|
||||
@@ -32,7 +34,7 @@ function Server(remote, opts) {
|
||||
throw new TypeError('Server configuration is not an Object');
|
||||
}
|
||||
|
||||
if (!Server.domainRE.test(opts.host)) {
|
||||
if (!Server.DOMAIN_RE.test(opts.host)) {
|
||||
throw new Error('Server host is malformed, use "host" and "port" server configuration');
|
||||
}
|
||||
|
||||
@@ -56,6 +58,8 @@ function Server(remote, opts) {
|
||||
this._connected = false;
|
||||
this._shouldConnect = false;
|
||||
this._state = 'offline';
|
||||
this._ledgerRanges = new RangeSet();
|
||||
this._ledgerMap = LRU({ max: 200 });
|
||||
|
||||
this._id = 0; // request ID
|
||||
this._retry = 0;
|
||||
@@ -117,31 +121,29 @@ function Server(remote, opts) {
|
||||
self._updateScore('loadchange', load);
|
||||
});
|
||||
|
||||
// If server is not up-to-date, request server_info
|
||||
// for getting pubkey_node & hostid information.
|
||||
// Otherwise this information is available on the
|
||||
// initial server subscribe response
|
||||
this.on('connect', function requestServerID() {
|
||||
if (self._pubkey_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.on('response_server_info', function setServerID(message) {
|
||||
try {
|
||||
self._pubkey_node = message.info.pubkey_node;
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
var serverInfoRequest = self._remote.requestServerInfo();
|
||||
serverInfoRequest.on('error', function() { });
|
||||
self._request(serverInfoRequest);
|
||||
this.on('connect', function() {
|
||||
self.requestServerID();
|
||||
});
|
||||
};
|
||||
|
||||
util.inherits(Server, EventEmitter);
|
||||
|
||||
Server.domainRE = /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?)*\.?$/;
|
||||
Server.DOMAIN_RE = /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|[-_]){0,61}[0-9A-Za-z])?)*\.?$/;
|
||||
|
||||
Server.TLS_ERRORS = [
|
||||
'UNABLE_TO_GET_ISSUER_CERT', 'UNABLE_TO_GET_CRL',
|
||||
'UNABLE_TO_DECRYPT_CERT_SIGNATURE', 'UNABLE_TO_DECRYPT_CRL_SIGNATURE',
|
||||
'UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY', 'CERT_SIGNATURE_FAILURE',
|
||||
'CRL_SIGNATURE_FAILURE', 'CERT_NOT_YET_VALID', 'CERT_HAS_EXPIRED',
|
||||
'CRL_NOT_YET_VALID', 'CRL_HAS_EXPIRED', 'ERROR_IN_CERT_NOT_BEFORE_FIELD',
|
||||
'ERROR_IN_CERT_NOT_AFTER_FIELD', 'ERROR_IN_CRL_LAST_UPDATE_FIELD',
|
||||
'ERROR_IN_CRL_NEXT_UPDATE_FIELD', 'OUT_OF_MEM',
|
||||
'DEPTH_ZERO_SELF_SIGNED_CERT', 'SELF_SIGNED_CERT_IN_CHAIN',
|
||||
'UNABLE_TO_GET_ISSUER_CERT_LOCALLY', 'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
|
||||
'CERT_CHAIN_TOO_LONG', 'CERT_REVOKED', 'INVALID_CA',
|
||||
'PATH_LENGTH_EXCEEDED', 'INVALID_PURPOSE', 'CERT_UNTRUSTED',
|
||||
'CERT_REJECTED'
|
||||
];
|
||||
|
||||
/**
|
||||
* Server states that we will treat as the server being online.
|
||||
@@ -235,6 +237,31 @@ Server.prototype._checkActivity = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* If server is not up-to-date, request server_info for getting pubkey_node
|
||||
* & hostid information. Otherwise this information is available on the
|
||||
* initial server subscribe response
|
||||
*/
|
||||
|
||||
Server.prototype.requestServerID = function() {
|
||||
var self = this;
|
||||
|
||||
if (this._pubkey_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.on('response_server_info', function setServerID(message) {
|
||||
try {
|
||||
self._pubkey_node = message.info.pubkey_node;
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
var serverInfoRequest = this._remote.requestServerInfo();
|
||||
serverInfoRequest.on('error', function() { });
|
||||
this._request(serverInfoRequest);
|
||||
};
|
||||
|
||||
/**
|
||||
* Server maintains a score for request prioritization.
|
||||
*
|
||||
@@ -328,6 +355,8 @@ Server.prototype.disconnect = function() {
|
||||
this._lastLedgerClose = NaN;
|
||||
this._score = 0;
|
||||
this._shouldConnect = false;
|
||||
this._ledgerRanges.reset();
|
||||
this._ledgerMap.reset();
|
||||
this._setState('offline');
|
||||
|
||||
if (this._ws) {
|
||||
@@ -420,6 +449,11 @@ Server.prototype.connect = function() {
|
||||
log.info(self.getServerID(), 'onerror:', e.data || e);
|
||||
}
|
||||
|
||||
if (Server.TLS_ERRORS.indexOf(e.message) !== -1) {
|
||||
// Unrecoverable
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Most connection errors for WebSockets are conveyed as 'close' events with
|
||||
// code 1006. This is done for security purposes and therefore unlikely to
|
||||
// ever change.
|
||||
@@ -545,6 +579,8 @@ Server.prototype._handleMessage = function(message) {
|
||||
Server.prototype._handleLedgerClosed = function(message) {
|
||||
this._lastLedgerIndex = message.ledger_index;
|
||||
this._lastLedgerClose = Date.now();
|
||||
this._ledgerRanges.add(message.ledger_index);
|
||||
this._ledgerMap.set(message.ledger_hash, message.ledger_index);
|
||||
this.emit('ledger_closed', message);
|
||||
};
|
||||
|
||||
@@ -620,24 +656,33 @@ Server.prototype._handlePathFind = function(message) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle subscription response messages. Subscription response
|
||||
* messages indicate that a connection to the server is ready
|
||||
* Handle initial subscription response message. The server is considered
|
||||
* `connected` after it has received a response to initial subscription to
|
||||
* ledger and server streams
|
||||
*
|
||||
* @param {Object} message
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Server.prototype._handleResponseSubscribe = function(message) {
|
||||
if (this.isConnected()) {
|
||||
// This function only concerns initializing the server's internal
|
||||
// state after a connection
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._remote._allow_partial_history
|
||||
&& !Server.hasFullLedgerHistory(message)) {
|
||||
// Server has partial history and Remote has been configured to disallow
|
||||
// servers with incomplete history
|
||||
return this.reconnect();
|
||||
}
|
||||
|
||||
if (message.pubkey_node) {
|
||||
// pubkey_node is used to identify the server
|
||||
this._pubkey_node = message.pubkey_node;
|
||||
}
|
||||
|
||||
if (Server.isLoadStatus(message)) {
|
||||
this._load_base = message.load_base || 256;
|
||||
this._load_factor = message.load_factor || 256;
|
||||
@@ -646,6 +691,12 @@ Server.prototype._handleResponseSubscribe = function(message) {
|
||||
this._reserve_base = message.reserve_base;
|
||||
this._reserve_inc = message.reserve_inc;
|
||||
}
|
||||
|
||||
if (message.validated_ledgers) {
|
||||
// Add validated ledgers to ledger range set
|
||||
this._ledgerRanges.add(message.validated_ledgers);
|
||||
}
|
||||
|
||||
if (~Server.onlineStates.indexOf(message.server_status)) {
|
||||
this._setState('online');
|
||||
}
|
||||
@@ -750,6 +801,12 @@ Server.prototype._request = function(request) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get server connected status
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
Server.prototype.isConnected =
|
||||
Server.prototype._isConnected = function() {
|
||||
return this._connected;
|
||||
@@ -824,6 +881,36 @@ Server.prototype._reserve = function(ownerCount) {
|
||||
return reserve_base.add(reserve_inc.product_human(owner_count));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check that server has seen closed ledger
|
||||
*
|
||||
* @param {string|number} ledger hash or index
|
||||
* @return boolean
|
||||
*/
|
||||
|
||||
Server.prototype.hasLedger = function(ledger) {
|
||||
var result = false;
|
||||
|
||||
if (typeof ledger === 'string' && /^[A-F0-9]{64}$/.test(ledger)) {
|
||||
result = this._ledgerMap.has(ledger);
|
||||
} else if (ledger != null && !isNaN(ledger)) {
|
||||
result = this._ledgerRanges.has(ledger);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get ledger index of last seen validated ledger
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
|
||||
Server.prototype.getLastLedger =
|
||||
Server.prototype.getLastLedgerIndex = function() {
|
||||
return this._lastLedgerIndex;
|
||||
};
|
||||
|
||||
exports.Server = Server;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
var Crypt = require('./crypt').Crypt;
|
||||
var Message = require('./message').Message;
|
||||
var parser = require("url");
|
||||
var querystring = require('querystring');
|
||||
var extend = require("extend");
|
||||
|
||||
var SignedRequest = function (config) {
|
||||
// XXX Constructor should be generalized and constructing from an Angular.js
|
||||
// $http config should be a SignedRequest.from... utility method.
|
||||
this.config = extend(true, {}, config);
|
||||
if (!this.config.data) this.config.data = {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a string from request parameters that
|
||||
* will be used to sign a request
|
||||
* @param {Object} parsed - parsed url
|
||||
* @param {Object} date
|
||||
* @param {Object} mechanism - type of signing
|
||||
*/
|
||||
SignedRequest.prototype.getStringToSign = function (parsed, date, mechanism) {
|
||||
// XXX This method doesn't handle signing GET requests correctly. The data
|
||||
// field will be merged into the search string, not the request body.
|
||||
|
||||
// Sort the properties of the JSON object into canonical form
|
||||
var canonicalData = JSON.stringify(copyObjectWithSortedKeys(this.config.data));
|
||||
|
||||
// Canonical request using Amazon's v4 signature format
|
||||
// See: http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
|
||||
var canonicalRequest = [
|
||||
this.config.method || 'GET',
|
||||
parsed.pathname || '',
|
||||
parsed.search || '',
|
||||
// XXX Headers signing not supported
|
||||
'',
|
||||
'',
|
||||
Crypt.hashSha512(canonicalData).toLowerCase()
|
||||
].join('\n');
|
||||
|
||||
// String to sign inspired by Amazon's v4 signature format
|
||||
// See: http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
||||
//
|
||||
// We don't have a credential scope, so we skip it.
|
||||
//
|
||||
// But that modifies the format, so the format ID is RIPPLE1, instead of AWS4.
|
||||
return [
|
||||
mechanism,
|
||||
date,
|
||||
Crypt.hashSha512(canonicalRequest).toLowerCase()
|
||||
].join('\n');
|
||||
};
|
||||
|
||||
//prepare for signing
|
||||
function copyObjectWithSortedKeys(object) {
|
||||
if (isPlainObject(object)) {
|
||||
var newObj = {};
|
||||
var keysSorted = Object.keys(object).sort();
|
||||
var key;
|
||||
for (var i in keysSorted) {
|
||||
key = keysSorted[i];
|
||||
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
||||
newObj[key] = copyObjectWithSortedKeys(object[key]);
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
} else if (Array.isArray(object)) {
|
||||
return object.map(copyObjectWithSortedKeys);
|
||||
} else {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
//from npm extend
|
||||
function isPlainObject(obj) {
|
||||
var hasOwn = Object.prototype.hasOwnProperty;
|
||||
var toString = Object.prototype.toString;
|
||||
|
||||
if (!obj || toString.call(obj) !== '[object Object]' || obj.nodeType || obj.setInterval)
|
||||
return false;
|
||||
|
||||
var has_own_constructor = hasOwn.call(obj, 'constructor');
|
||||
var has_is_property_of_method = hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
|
||||
// Not own constructor property must be Object
|
||||
if (obj.constructor && !has_own_constructor && !has_is_property_of_method)
|
||||
return false;
|
||||
|
||||
// Own properties are enumerated firstly, so to speed up,
|
||||
// if last one is own, then all properties are own.
|
||||
var key;
|
||||
for ( key in obj ) {}
|
||||
|
||||
return key === undefined || hasOwn.call( obj, key );
|
||||
};
|
||||
|
||||
/**
|
||||
* HMAC signed request
|
||||
* @param {Object} config
|
||||
* @param {Object} auth_secret
|
||||
* @param {Object} blob_id
|
||||
*/
|
||||
SignedRequest.prototype.signHmac = function (auth_secret, blob_id) {
|
||||
var config = extend(true, {}, this.config);
|
||||
|
||||
// Parse URL
|
||||
var parsed = parser.parse(config.url);
|
||||
var date = dateAsIso8601();
|
||||
var signatureType = 'RIPPLE1-HMAC-SHA512';
|
||||
var stringToSign = this.getStringToSign(parsed, date, signatureType);
|
||||
var signature = Crypt.signString(auth_secret, stringToSign);
|
||||
|
||||
var query = querystring.stringify({
|
||||
signature: Crypt.base64ToBase64Url(signature),
|
||||
signature_date: date,
|
||||
signature_blob_id: blob_id,
|
||||
signature_type: signatureType
|
||||
});
|
||||
|
||||
config.url += (parsed.search ? '&' : '?') + query;
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asymmetric signed request
|
||||
* @param {Object} config
|
||||
* @param {Object} secretKey
|
||||
* @param {Object} account
|
||||
* @param {Object} blob_id
|
||||
*/
|
||||
SignedRequest.prototype.signAsymmetric = function (secretKey, account, blob_id) {
|
||||
var config = extend(true, {}, this.config);
|
||||
|
||||
// Parse URL
|
||||
var parsed = parser.parse(config.url);
|
||||
var date = dateAsIso8601();
|
||||
var signatureType = 'RIPPLE1-ECDSA-SHA512';
|
||||
var stringToSign = this.getStringToSign(parsed, date, signatureType);
|
||||
var signature = Message.signMessage(stringToSign, secretKey);
|
||||
|
||||
var query = querystring.stringify({
|
||||
signature: Crypt.base64ToBase64Url(signature),
|
||||
signature_date: date,
|
||||
signature_blob_id: blob_id,
|
||||
signature_account: account,
|
||||
signature_type: signatureType
|
||||
});
|
||||
|
||||
config.url += (parsed.search ? '&' : '?') + query;
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asymmetric signed request for vault recovery
|
||||
* @param {Object} config
|
||||
* @param {Object} secretKey
|
||||
* @param {Object} username
|
||||
*/
|
||||
SignedRequest.prototype.signAsymmetricRecovery = function (secretKey, username) {
|
||||
var config = extend(true, {}, this.config);
|
||||
|
||||
// Parse URL
|
||||
var parsed = parser.parse(config.url);
|
||||
var date = dateAsIso8601();
|
||||
var signatureType = 'RIPPLE1-ECDSA-SHA512';
|
||||
var stringToSign = this.getStringToSign(parsed, date, signatureType);
|
||||
var signature = Message.signMessage(stringToSign, secretKey);
|
||||
|
||||
var query = querystring.stringify({
|
||||
signature: Crypt.base64ToBase64Url(signature),
|
||||
signature_date: date,
|
||||
signature_username: username,
|
||||
signature_type: signatureType
|
||||
});
|
||||
|
||||
config.url += (parsed.search ? '&' : '?') + query;
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
var dateAsIso8601 = (function () {
|
||||
function pad(n) {
|
||||
return (n < 0 || n > 9 ? "" : "0") + n;
|
||||
}
|
||||
|
||||
return function dateAsIso8601() {
|
||||
var date = new Date();
|
||||
return date.getUTCFullYear() + "-" +
|
||||
pad(date.getUTCMonth() + 1) + "-" +
|
||||
pad(date.getUTCDate()) + "T" +
|
||||
pad(date.getUTCHours()) + ":" +
|
||||
pad(date.getUTCMinutes()) + ":" +
|
||||
pad(date.getUTCSeconds()) + ".000Z";
|
||||
};
|
||||
})();
|
||||
|
||||
// XXX Add methods for verifying requests
|
||||
// SignedRequest.prototype.verifySignatureHmac
|
||||
// SignedRequest.prototype.verifySignatureAsymetric
|
||||
|
||||
exports.SignedRequest = SignedRequest;
|
||||
|
||||
@@ -11,6 +11,7 @@ var SerializedObject = require('./serializedobject').SerializedObject;
|
||||
var RippleError = require('./rippleerror').RippleError;
|
||||
var hashprefixes = require('./hashprefixes');
|
||||
var config = require('./config');
|
||||
var log = require('./log').internal.sub('transaction');
|
||||
|
||||
/**
|
||||
* @constructor Transaction
|
||||
@@ -131,6 +132,7 @@ Transaction.set_clear_flags = {
|
||||
asfRequireAuth: 2,
|
||||
asfDisallowXRP: 3,
|
||||
asfDisableMaster: 4,
|
||||
asfAccountTxnID: 5,
|
||||
asfNoFreeze: 6,
|
||||
asfGlobalFreeze: 7
|
||||
}
|
||||
@@ -858,6 +860,15 @@ Transaction.prototype.addMemo = function(memoType, memoFormat, memoData) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Transaction.prototype.setAccountTxnID =
|
||||
Transaction.prototype.accountTxnID = function(id) {
|
||||
if (typeof id === 'string') {
|
||||
this.tx_json.AccountTxnID = id;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct an 'AccountSet' transaction
|
||||
*
|
||||
@@ -1160,7 +1171,7 @@ Transaction.prototype.abort = function() {
|
||||
* @return {Object} transaction summary
|
||||
*/
|
||||
|
||||
Transaction.summary = function() {
|
||||
Transaction.prototype.summary = function() {
|
||||
var result = {
|
||||
tx_json: this.tx_json,
|
||||
clientID: this._clientID,
|
||||
|
||||
@@ -200,10 +200,10 @@ TransactionManager.prototype._adjustFees = function() {
|
||||
};
|
||||
|
||||
this._pending.forEach(function(transaction) {
|
||||
if (transaction._setFixedFee === true) {
|
||||
if (transaction._setFixedFee) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var oldFee = transaction.tx_json.Fee;
|
||||
var newFee = transaction._computeFee();
|
||||
|
||||
@@ -243,7 +243,7 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
||||
assert.strictEqual(typeof ledger, 'object');
|
||||
assert.strictEqual(typeof ledger.ledger_index, 'number');
|
||||
|
||||
this._pending.forEach(function(transaction) {
|
||||
this._pending.forEach(function(transaction) {
|
||||
switch (ledger.ledger_index - transaction.submitIndex) {
|
||||
case 4:
|
||||
transaction.emit('missing', ledger);
|
||||
@@ -313,6 +313,7 @@ TransactionManager.prototype._fillSequence = function(tx, callback) {
|
||||
* Load account transaction sequence
|
||||
*
|
||||
* @param [Function] callback
|
||||
* @api private
|
||||
*/
|
||||
|
||||
TransactionManager.prototype._loadSequence = function(callback) {
|
||||
@@ -347,7 +348,7 @@ TransactionManager.prototype._handleReconnect = function(callback) {
|
||||
var self = this;
|
||||
var callback = (typeof callback === 'function') ? callback : function(){};
|
||||
|
||||
if (!this._pending.length) {
|
||||
if (!this._pending.length()) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
@@ -390,6 +391,7 @@ TransactionManager.prototype._handleReconnect = function(callback) {
|
||||
*
|
||||
* @param {Number} ledgers
|
||||
* @param {Function} callback
|
||||
* @api private
|
||||
*/
|
||||
|
||||
TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
|
||||
@@ -419,6 +421,7 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
|
||||
*
|
||||
* @param [Number] ledgers to wait before resubmitting
|
||||
* @param [Transaction] pending transactions to resubmit
|
||||
* @api private
|
||||
*/
|
||||
|
||||
TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
||||
@@ -436,7 +439,13 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
||||
var received = transaction.findId(self._pending._idCache);
|
||||
|
||||
if (received) {
|
||||
return transaction.emit('success', received);
|
||||
switch (received.engine_result) {
|
||||
case 'tesSUCCESS':
|
||||
transaction.emit('success', received);
|
||||
break;
|
||||
default:
|
||||
transaction.emit('error', received);
|
||||
}
|
||||
}
|
||||
|
||||
while (self._pending.hasSequence(transaction.tx_json.Sequence)) {
|
||||
@@ -470,6 +479,7 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
||||
*
|
||||
* @param {Transaction} transaction to submit
|
||||
* @return {Request} submit request
|
||||
* @api private
|
||||
*/
|
||||
|
||||
TransactionManager.prototype._prepareRequest = function(tx) {
|
||||
@@ -501,6 +511,7 @@ TransactionManager.prototype._prepareRequest = function(tx) {
|
||||
* Send `submit` request, handle response
|
||||
*
|
||||
* @param {Transaction} transaction to submit
|
||||
* @api private
|
||||
*/
|
||||
|
||||
TransactionManager.prototype._request = function(tx) {
|
||||
@@ -645,7 +656,7 @@ TransactionManager.prototype._request = function(tx) {
|
||||
|
||||
tx.emit('presubmit');
|
||||
|
||||
tx.submissions = submitRequest.broadcast();
|
||||
submitRequest.broadcast().request();
|
||||
tx.attempts++;
|
||||
|
||||
tx.emit('postsubmit');
|
||||
|
||||
@@ -13,7 +13,6 @@ var BigInteger = utils.jsbn.BigInteger;
|
||||
var UInt = function() {
|
||||
// Internal form: NaN or BigInteger
|
||||
this._value = NaN;
|
||||
|
||||
this._update();
|
||||
};
|
||||
|
||||
@@ -96,6 +95,10 @@ UInt.prototype.clone = function() {
|
||||
UInt.prototype.copyTo = function(d) {
|
||||
d._value = this._value;
|
||||
|
||||
if (this._version_byte !== void(0)) {
|
||||
d._version_byte = this._version_byte;
|
||||
}
|
||||
|
||||
if (typeof d._update === 'function') {
|
||||
d._update();
|
||||
}
|
||||
@@ -104,7 +107,9 @@ UInt.prototype.copyTo = function(d) {
|
||||
};
|
||||
|
||||
UInt.prototype.equals = function(d) {
|
||||
return this._value instanceof BigInteger && d._value instanceof BigInteger && this._value.equals(d._value);
|
||||
return this._value instanceof BigInteger
|
||||
&& d._value instanceof BigInteger
|
||||
&& this._value.equals(d._value);
|
||||
};
|
||||
|
||||
UInt.prototype.is_valid = function() {
|
||||
|
||||
@@ -1,593 +0,0 @@
|
||||
var async = require('async');
|
||||
var blobClient = require('./blob').BlobClient;
|
||||
var AuthInfo = require('./authinfo').AuthInfo;
|
||||
var crypt = require('./crypt').Crypt;
|
||||
var log = require('./log').sub('vault');
|
||||
function VaultClient(opts) {
|
||||
|
||||
var self = this;
|
||||
|
||||
if (!opts) {
|
||||
opts = { };
|
||||
}
|
||||
|
||||
if (typeof opts === 'string') {
|
||||
opts = { domain: opts };
|
||||
}
|
||||
|
||||
this.domain = opts.domain || 'ripple.com';
|
||||
this.infos = { };
|
||||
};
|
||||
|
||||
/**
|
||||
* getAuthInfo
|
||||
* gets auth info for a username. returns authinfo
|
||||
* even if user does not exists (with exist set to false)
|
||||
* @param {string} username
|
||||
* @param {function} callback
|
||||
*/
|
||||
VaultClient.prototype.getAuthInfo = function (username, callback) {
|
||||
|
||||
AuthInfo.get(this.domain, username, function(err, authInfo) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (authInfo.version !== 3) {
|
||||
return callback(new Error('This wallet is incompatible with this version of the vault-client.'));
|
||||
}
|
||||
|
||||
if (!authInfo.pakdf) {
|
||||
return callback(new Error('No settings for PAKDF in auth packet.'));
|
||||
}
|
||||
|
||||
if (typeof authInfo.blobvault !== 'string') {
|
||||
return callback(new Error('No blobvault specified in the authinfo.'));
|
||||
}
|
||||
|
||||
callback(null, authInfo);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* _deriveLoginKeys
|
||||
* method designed for asnyc waterfall
|
||||
*/
|
||||
|
||||
VaultClient.prototype._deriveLoginKeys = function (authInfo, password, callback) {
|
||||
var normalizedUsername = authInfo.username.toLowerCase().replace(/-/g, '');
|
||||
|
||||
//derive login keys
|
||||
crypt.derive(authInfo.pakdf, 'login', normalizedUsername, password, function(err, keys) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, authInfo, password, keys);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* _deriveUnlockKey
|
||||
* method designed for asnyc waterfall
|
||||
*/
|
||||
|
||||
VaultClient.prototype._deriveUnlockKey = function (authInfo, password, keys, callback) {
|
||||
var normalizedUsername = authInfo.username.toLowerCase().replace(/-/g, '');
|
||||
|
||||
//derive unlock key
|
||||
crypt.derive(authInfo.pakdf, 'unlock', normalizedUsername, password, function(err, unlock) {
|
||||
if (err) {
|
||||
log.error('derive:', err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!keys) {
|
||||
keys = { };
|
||||
}
|
||||
|
||||
keys.unlock = unlock.unlock;
|
||||
callback(null, authInfo, keys);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a ripple name from a given account address, if it has one
|
||||
* @param {string} address - Account address to query
|
||||
* @param {string} url - Url of blob vault
|
||||
*/
|
||||
|
||||
VaultClient.prototype.getRippleName = function(address, url, callback) {
|
||||
//use the url from previously retrieved authInfo, if necessary
|
||||
if (!url) {
|
||||
callback(new Error('Blob vault URL is required'));
|
||||
} else {
|
||||
blobClient.getRippleName(url, address, callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check blobvault for existance of username
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.exists = function(username, callback) {
|
||||
AuthInfo.get(this.domain, username.toLowerCase(), function(err, authInfo) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, !!authInfo.exists);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Authenticate and retrieve a decrypted blob using a ripple name and password
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.login = function(username, password, device_id, callback) {
|
||||
var self = this;
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
getBlob
|
||||
];
|
||||
|
||||
async.waterfall(steps, callback);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(username, function(err, authInfo){
|
||||
|
||||
if (authInfo && !authInfo.exists) {
|
||||
return callback(new Error('User does not exist.'));
|
||||
}
|
||||
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
}
|
||||
|
||||
function getBlob(authInfo, password, keys, callback) {
|
||||
var options = {
|
||||
url : authInfo.blobvault,
|
||||
blob_id : keys.id,
|
||||
key : keys.crypt,
|
||||
device_id : device_id
|
||||
};
|
||||
|
||||
blobClient.get(options, function(err, blob) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
//save for relogin
|
||||
self.infos[keys.id] = authInfo;
|
||||
|
||||
//migrate missing fields
|
||||
if (blob.missing_fields) {
|
||||
if (blob.missing_fields.encrypted_blobdecrypt_key) {
|
||||
log.info('migration: saving encrypted blob decrypt key');
|
||||
authInfo.blob = blob;
|
||||
//get the key to unlock the secret, then update the blob keys
|
||||
self._deriveUnlockKey(authInfo, password, keys, updateKeys);
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
blob : blob,
|
||||
username : authInfo.username,
|
||||
verified : authInfo.emailVerified
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function updateKeys (err, params, keys) {
|
||||
if (err || !keys.unlock) {
|
||||
return; //unable to unlock
|
||||
}
|
||||
|
||||
var secret;
|
||||
try {
|
||||
secret = crypt.decrypt(keys.unlock, params.blob.encrypted_secret);
|
||||
} catch (error) {
|
||||
return log.error('decrypt:', error);
|
||||
}
|
||||
|
||||
options = {
|
||||
username : params.username,
|
||||
blob : params.blob,
|
||||
masterkey : secret,
|
||||
keys : keys
|
||||
};
|
||||
|
||||
blobClient.updateKeys(options, function(err, resp){
|
||||
if (err) {
|
||||
log.error('updateKeys:', err);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retreive and decrypt blob using a blob url, id and crypt derived previously.
|
||||
*
|
||||
* @param {string} url - Blob vault url
|
||||
* @param {string} id - Blob id from previously retreived blob
|
||||
* @param {string} key - Blob decryption key
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.relogin = function(url, id, key, device_id, callback) {
|
||||
//use the url from previously retrieved authInfo, if necessary
|
||||
if (!url && this.infos[id]) {
|
||||
url = this.infos[id].blobvault;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
return callback(new Error('Blob vault URL is required'));
|
||||
}
|
||||
|
||||
var options = {
|
||||
url : url,
|
||||
blob_id : id,
|
||||
key : key,
|
||||
device_id : device_id
|
||||
};
|
||||
|
||||
blobClient.get(options, function(err, blob) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback (null, { blob: blob });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypt the secret key using a username and password
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @param {string} encryptSecret
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.unlock = function(username, password, encryptSecret, fn) {
|
||||
var self = this;
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveUnlockKey,
|
||||
unlockSecret
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(username, function(err, authInfo){
|
||||
|
||||
if (authInfo && !authInfo.exists) {
|
||||
return callback(new Error('User does not exist.'));
|
||||
}
|
||||
|
||||
return callback (err, authInfo, password, {});
|
||||
});
|
||||
}
|
||||
|
||||
function unlockSecret (authinfo, keys, callback) {
|
||||
|
||||
var secret;
|
||||
try {
|
||||
secret = crypt.decrypt(keys.unlock, encryptSecret);
|
||||
} catch (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
keys : keys,
|
||||
secret : secret
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the decrypted blob and secret key in one step using
|
||||
* the username and password
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} password
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.loginAndUnlock = function(username, password, device_id, fn) {
|
||||
var self = this;
|
||||
|
||||
var steps = [
|
||||
login,
|
||||
deriveUnlockKey,
|
||||
unlockSecret
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function login (callback) {
|
||||
self.login(username, password, device_id, function(err, resp) {
|
||||
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (!resp.blob || !resp.blob.encrypted_secret) {
|
||||
return callback(new Error('Unable to retrieve blob and secret.'));
|
||||
}
|
||||
|
||||
if (!resp.blob.id || !resp.blob.key) {
|
||||
return callback(new Error('Unable to retrieve keys.'));
|
||||
}
|
||||
|
||||
//get authInfo via id - would have been saved from login
|
||||
var authInfo = self.infos[resp.blob.id];
|
||||
|
||||
if (!authInfo) {
|
||||
return callback(new Error('Unable to find authInfo'));
|
||||
}
|
||||
|
||||
callback(null, authInfo, password, resp.blob);
|
||||
});
|
||||
};
|
||||
|
||||
function deriveUnlockKey (authInfo, password, blob, callback) {
|
||||
self._deriveUnlockKey(authInfo, password, null, function(err, authInfo, keys){
|
||||
callback(err, keys.unlock, authInfo, blob);
|
||||
});
|
||||
};
|
||||
|
||||
function unlockSecret (unlock, authInfo, blob, callback) {
|
||||
var secret;
|
||||
try {
|
||||
secret = crypt.decrypt(unlock, blob.encrypted_secret);
|
||||
} catch (error) {
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
blob : blob,
|
||||
unlock : unlock,
|
||||
secret : secret,
|
||||
username : authInfo.username,
|
||||
verified : authInfo.emailVerified
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify an email address for an existing user
|
||||
*
|
||||
* @param {string} username
|
||||
* @param {string} token - Verification token
|
||||
* @param {function} fn - Callback function
|
||||
*/
|
||||
|
||||
VaultClient.prototype.verify = function(username, token, callback) {
|
||||
var self = this;
|
||||
|
||||
self.getAuthInfo(username, function (err, authInfo){
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
blobClient.verify(authInfo.blobvault, username.toLowerCase(), token, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* changePassword
|
||||
* @param {object} options
|
||||
* @param {string} options.username
|
||||
* @param {string} options.password
|
||||
* @param {string} options.masterkey
|
||||
* @param {object} options.blob
|
||||
*/
|
||||
|
||||
VaultClient.prototype.changePassword = function (options, fn) {
|
||||
var self = this;
|
||||
var password = String(options.password).trim();
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
self._deriveUnlockKey,
|
||||
changePassword
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(options.username, function(err, authInfo) {
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
};
|
||||
|
||||
function changePassword (authInfo, keys, callback) {
|
||||
options.keys = keys;
|
||||
blobClient.updateKeys(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* rename
|
||||
* rename a ripple account
|
||||
* @param {object} options
|
||||
* @param {string} options.username
|
||||
* @param {string} options.new_username
|
||||
* @param {string} options.password
|
||||
* @param {string} options.masterkey
|
||||
* @param {object} options.blob
|
||||
* @param {function} fn
|
||||
*/
|
||||
|
||||
VaultClient.prototype.rename = function (options, fn) {
|
||||
var self = this;
|
||||
var new_username = String(options.new_username).trim();
|
||||
var password = String(options.password).trim();
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
self._deriveUnlockKey,
|
||||
renameBlob
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(new_username, function(err, authInfo){
|
||||
|
||||
if (authInfo && authInfo.exists) {
|
||||
return callback(new Error('username already taken.'));
|
||||
} else {
|
||||
authInfo.username = new_username;
|
||||
}
|
||||
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
};
|
||||
|
||||
function renameBlob (authInfo, keys, callback) {
|
||||
options.keys = keys;
|
||||
blobClient.rename(options, callback);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a new user and save to the blob vault
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {string} options.username
|
||||
* @param {string} options.password
|
||||
* @param {string} options.masterkey //optional, will create if absent
|
||||
* @param {string} options.email
|
||||
* @param {string} options.activateLink
|
||||
* @param {object} options.oldUserBlob //optional
|
||||
* @param {function} fn
|
||||
*/
|
||||
|
||||
VaultClient.prototype.register = function(options, fn) {
|
||||
var self = this;
|
||||
var username = String(options.username).trim();
|
||||
var password = String(options.password).trim();
|
||||
var result = self.validateUsername(username);
|
||||
|
||||
if (!result.valid) {
|
||||
return fn(new Error('invalid username.'));
|
||||
}
|
||||
|
||||
var steps = [
|
||||
getAuthInfo,
|
||||
self._deriveLoginKeys,
|
||||
self._deriveUnlockKey,
|
||||
create
|
||||
];
|
||||
|
||||
async.waterfall(steps, fn);
|
||||
|
||||
function getAuthInfo(callback) {
|
||||
self.getAuthInfo(username, function(err, authInfo){
|
||||
return callback (err, authInfo, password);
|
||||
});
|
||||
};
|
||||
|
||||
function create(authInfo, keys, callback) {
|
||||
var params = {
|
||||
url : authInfo.blobvault,
|
||||
id : keys.id,
|
||||
crypt : keys.crypt,
|
||||
unlock : keys.unlock,
|
||||
username : username,
|
||||
email : options.email,
|
||||
masterkey : options.masterkey || crypt.createMaster(),
|
||||
activateLink : options.activateLink,
|
||||
oldUserBlob : options.oldUserBlob,
|
||||
domain : options.domain
|
||||
};
|
||||
|
||||
blobClient.create(params, function(err, blob) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, {
|
||||
blob : blob,
|
||||
username : username
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* validateUsername
|
||||
* check username for validity
|
||||
*/
|
||||
|
||||
VaultClient.prototype.validateUsername = function (username) {
|
||||
username = String(username).trim();
|
||||
var result = {
|
||||
valid : false,
|
||||
reason : ''
|
||||
};
|
||||
|
||||
if (username.length < 2) {
|
||||
result.reason = 'tooshort';
|
||||
} else if (username.length > 20) {
|
||||
result.reason = 'toolong';
|
||||
} else if (!/^[a-zA-Z0-9\-]+$/.exec(username)) {
|
||||
result.reason = 'charset';
|
||||
} else if (/^-/.exec(username)) {
|
||||
result.reason = 'starthyphen';
|
||||
} else if (/-$/.exec(username)) {
|
||||
result.reason = 'endhyphen';
|
||||
} else if (/--/.exec(username)) {
|
||||
result.reason = 'multhyphen';
|
||||
} else {
|
||||
result.valid = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* generateDeviceID
|
||||
* create a new random device ID for 2FA
|
||||
*/
|
||||
VaultClient.prototype.generateDeviceID = function () {
|
||||
return crypt.createSecret(4);
|
||||
};
|
||||
|
||||
/*** pass thru some blob client function ***/
|
||||
|
||||
VaultClient.prototype.resendEmail = blobClient.resendEmail;
|
||||
|
||||
VaultClient.prototype.recoverBlob = blobClient.recoverBlob;
|
||||
|
||||
VaultClient.prototype.deleteBlob = blobClient.deleteBlob;
|
||||
|
||||
VaultClient.prototype.requestToken = blobClient.requestToken;
|
||||
|
||||
VaultClient.prototype.verifyToken = blobClient.verifyToken;
|
||||
|
||||
VaultClient.prototype.getAttestation = blobClient.getAttestation;
|
||||
|
||||
VaultClient.prototype.updateAttestation = blobClient.updateAttestation;
|
||||
|
||||
VaultClient.prototype.getAttestationSummary = blobClient.getAttestationSummary;
|
||||
|
||||
//export by name
|
||||
exports.VaultClient = VaultClient;
|
||||
@@ -1,5 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var Account = require('../src/js/ripple/account').Account;
|
||||
var Account = require('ripple-lib').Account;
|
||||
|
||||
describe('Account', function(){
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var BigInteger = require('../src/js/jsbn/jsbn').BigInteger;
|
||||
var Amount = utils.load_module('amount').Amount;
|
||||
var UInt160 = utils.load_module('uint160').UInt160;
|
||||
var config = utils.get_config();
|
||||
var assert = require('assert');
|
||||
var BigInteger = require('ripple-lib').jsbn.BigInteger;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var UInt160 = require('ripple-lib').UInt160;
|
||||
var load_config = require('ripple-lib').config.load;
|
||||
var config = require('./config-example');
|
||||
|
||||
load_config(config);
|
||||
|
||||
|
||||
describe('Amount', function() {
|
||||
describe('Negatives', function() {
|
||||
@@ -1196,7 +1199,6 @@ describe('Amount', function() {
|
||||
});
|
||||
|
||||
it ('from_json minimum XRP', function() {
|
||||
console.log('max', Amount.bi_xns_max.toString());
|
||||
var amt = Amount.from_json('-9000000000000000000');
|
||||
assert.strictEqual(amt.to_json(), '-9000000000000000000');
|
||||
});
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Seed = utils.load_module('seed').Seed;
|
||||
var config = require('./testutils').get_config();
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
describe('Base58', function() {
|
||||
describe('Seed', function() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var currency = utils.load_module('currency').Currency;
|
||||
var timeUtil = utils.load_module('utils').time;
|
||||
var currency = require('ripple-lib').Currency;
|
||||
var timeUtil = require('ripple-lib').utils.time;
|
||||
|
||||
describe('Currency', function() {
|
||||
describe('json_rewrite', function() {
|
||||
|
||||
797
test/fixtures/binary-account-transaction.json
vendored
Normal file
797
test/fixtures/binary-account-transaction.json
vendored
Normal file
@@ -0,0 +1,797 @@
|
||||
{
|
||||
"OfferCreate": {
|
||||
"binary": {
|
||||
"ledger_index": 10983428,
|
||||
"meta": "201C00000000F8E311006F561C0662854F6571DD28392C1AF031757BDF2BC0E62C190ABE0BC22C46A2E443FDE824000263F550107B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE0064400000032A0D8DB065D4838D7EA4C6800000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D1811473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1E51100645642EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DFE722000000005842EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DF821473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1E4110064567B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400E72200000000365F04CE166242F400587B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F40001110000000000000000000000000000000000000000021100000000000000000000000000000000000000000311000000000000000000000000425443000000000004110A20B3C85F482532A9578DBB3950B85CA06594D1E1E1E3110064567B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00E8365F04D40AEE52AE00587B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE000311000000000000000000000000425443000000000004110A20B3C85F482532A9578DBB3950B85CA06594D1E1E1E411006F56CDD61BD2DF2ADF53D0C05C171E2C8D48337BFE63868497BC30C5DCF2D0A03AFFE7220000000024000263E72500A79550330000000000000000340000000000000000550F60460F66E991AE6D77C50435E7FF8915453D411B6E43B38AC6410113B06CDC50107B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400644000000326266D2065D4838D7EA4C6800000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D1811473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1E51100612500A7974E55329262FE69DD4F191AF0CE075489E7B7BDD273EC5528531D8184E1A73E76B7D356E0A052DA53A0D6F6C16422D206D4E38862ED7A13AE90ED0EF5ED09353C2A7A94E624000263F56240000005F01B0F39E1E7220000000024000263F62D000000096240000005F01AE829811473DFB1F8FDE93B1E301897694F0DDE56516BDC40E1E1F1031000",
|
||||
"tx_blob": "120007228000000024000263F52019000263E764400000032A0D8DB065D4838D7EA4C6800000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D1684000000000002710732103CDF7533BF6B6DE8C1AEFC1F2F776F8EDAE08D88C6E1F9B69535D9CDDF3071029744630440220153DDCA438981E498EF3AF383845F74B2CC20602FD1E20546A067C68D026DE6502207E4ECB4A23FFBC274CE0C2D08131F26FDDB6240B2A701C8E49410E0F18595053811473DFB1F8FDE93B1E301897694F0DDE56516BDC40",
|
||||
"validated": true
|
||||
},
|
||||
"parsed": {
|
||||
"validated": true,
|
||||
"meta": {
|
||||
"TransactionIndex": 0,
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "1C0662854F6571DD28392C1AF031757BDF2BC0E62C190ABE0BC22C46A2E443FD",
|
||||
"NewFields": {
|
||||
"Sequence": 156661,
|
||||
"BookDirectory": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00",
|
||||
"TakerPays": "13590433200",
|
||||
"TakerGets": {
|
||||
"value": "1",
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "42EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DF",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"RootIndex": "42EE066C2D6E683C6FDC95C3C0EF88B3D7C10E31E9D98060F517F18AD98217DF",
|
||||
"Owner": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"ExchangeRate": "5F04CE166242F400",
|
||||
"RootIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400",
|
||||
"TakerPaysCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsCurrency": "0000000000000000000000004254430000000000",
|
||||
"TakerGetsIssuer": "0A20B3C85F482532A9578DBB3950B85CA06594D1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00",
|
||||
"NewFields": {
|
||||
"ExchangeRate": "5F04D40AEE52AE00",
|
||||
"RootIndex": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04D40AEE52AE00",
|
||||
"TakerGetsCurrency": "0000000000000000000000004254430000000000",
|
||||
"TakerGetsIssuer": "0A20B3C85F482532A9578DBB3950B85CA06594D1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "CDD61BD2DF2ADF53D0C05C171E2C8D48337BFE63868497BC30C5DCF2D0A03AFF",
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 156647,
|
||||
"PreviousTxnLgrSeq": 10982736,
|
||||
"BookNode": "0000000000000000",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "0F60460F66E991AE6D77C50435E7FF8915453D411B6E43B38AC6410113B06CDC",
|
||||
"BookDirectory": "7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F04CE166242F400",
|
||||
"TakerPays": "13524954400",
|
||||
"TakerGets": {
|
||||
"value": "1",
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"PreviousTxnLgrSeq": 10983246,
|
||||
"PreviousTxnID": "329262FE69DD4F191AF0CE075489E7B7BDD273EC5528531D8184E1A73E76B7D3",
|
||||
"LedgerIndex": "E0A052DA53A0D6F6C16422D206D4E38862ED7A13AE90ED0EF5ED09353C2A7A94",
|
||||
"PreviousFields": {
|
||||
"Sequence": 156661,
|
||||
"Balance": "25503141689"
|
||||
},
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Sequence": 156662,
|
||||
"OwnerCount": 9,
|
||||
"Balance": "25503131689",
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx": {
|
||||
"TransactionType": "OfferCreate",
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 156661,
|
||||
"OfferSequence": 156647,
|
||||
"TakerPays": "13590433200",
|
||||
"TakerGets": {
|
||||
"value": "1",
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B"
|
||||
},
|
||||
"Fee": "10000",
|
||||
"SigningPubKey": "03CDF7533BF6B6DE8C1AEFC1F2F776F8EDAE08D88C6E1F9B69535D9CDDF3071029",
|
||||
"TxnSignature": "30440220153DDCA438981E498EF3AF383845F74B2CC20602FD1E20546A067C68D026DE6502207E4ECB4A23FFBC274CE0C2D08131F26FDDB6240B2A701C8E49410E0F18595053",
|
||||
"Account": "rBZgggUbdV7wHF1d7BRu1BLsxQqKHX3SN4",
|
||||
"hash": "3CC8ED34260911194E8E30543D70A6DF04D3DABC746A546DAED32D22496B478C",
|
||||
"inLedger": 10983428,
|
||||
"ledger_index": 10983428
|
||||
}
|
||||
}
|
||||
},
|
||||
"PartialPayment": {
|
||||
"binary": {
|
||||
"ledger_index": 11234994,
|
||||
"meta": "201C000000126012D4038D7EA4C680010000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6AF8E51100612500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A75653539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03E6240000016962400000C7C1B0629EE1E72200000000240000016A2D0000001662400000C7C1B033BE8114E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E51100722500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7565A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DEE66294CDB50C7C41DBBA0000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E722000200003700000000000000433800000000000000006294CD472C93E8BFBD0000000000000000000000004A5059000000000000000000000000000000000000000000000000016680000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD46780000000000000000000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E511006F2500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7566CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BBE664D5844871834DEC610000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D4E3860923E65C0000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1E1E72200020000240000DFA82A1C51809E33000000000000000034000000000000062D50103B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F964D5844855628F5EC90000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D4E3851FD80BB80000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1811488F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A756785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26E662940E35FA931A000000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E7220002000037000000000000027D380000000000000000629411C37937E080010000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D503E871B540C0000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6AE1E1E51100722500AB6E1455E6190463C940CFE3D75B031D95768F55F8F5E163EEB460AE6ED003784FDBC06B567A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0E6629544C2582DF5BB4000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E72200220000370000000000000288380000000000000000629544C255D8B8AA400000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D5438D7EA4C68000000000000000000000000000555344000000000088F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500AB6DED55D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A756ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACFE662D5C3F42A882475860000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E7220011000020123B9ACA0037000000000000000038000000000000004662D5C3F42D583783AE0000000000000000000000004A50590000000000000000000000000000000000000000000000000166D5CAA87BEE5380000000000000000000000000004A5059000000000088F647BBEC01AE19BE070B8B91063D14CE77F5236780000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD4E1E1F1031000",
|
||||
"tx_blob": "12000022800200002400000169201B00AB6EB461D4838D7EA4C680000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6A684000000000002EE069D4844ABF137B17EA0000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337732102AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D374463044022010E0D6884B36694342958C4872D7BADB825F36E6972757870665DD49580949A30220475F4CEA2904D23148AF51F194973AC73BDB986DA94BD9DEF51A5BBB9D7426108114E81DCB25DAA1DDEFF45145D334C56F12EA63C3378314625E2F1F09A0D769E05C04FAA64F0D2013306C6A011201E5C92828261DBAAC933B6309C6F5C72AF020AFD43000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD41000000000000000000000000000000000000000003000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4100000000000000000000000000000000000000000300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD3FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD300",
|
||||
"validated": true
|
||||
},
|
||||
"parsed": {
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Balance": "857948042174",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 22,
|
||||
"Sequence": 362
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "53539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03",
|
||||
"PreviousFields": {
|
||||
"Balance": "857948054174",
|
||||
"Sequence": 361
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-37.37431482875837"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000043"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "5A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DE",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-38.5823992616441"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F9",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 475103390,
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "000000000000062D",
|
||||
"Sequence": 57256,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.97996"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12054.31469825737"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "6CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BB",
|
||||
"PreviousFields": {
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.98998"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12055.52278269025"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.05000000000000001"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "110"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000027D"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.04"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1339.573870832192"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "1000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000288"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "7A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1339.583890832192"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "E6190463C940CFE3D75B031D95768F55F8F5E163EEB460AE6ED003784FDBC06B",
|
||||
"PreviousTxnLgrSeq": 11234836
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111290.052087083"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000046",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "300000"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"LowQualityIn": 1000000000
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACF",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111288.8440026502"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"PreviousTxnLgrSeq": 11234797
|
||||
}
|
||||
}
|
||||
],
|
||||
"DeliveredAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01000000000000001"
|
||||
},
|
||||
"TransactionIndex": 18,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01000000000000001"
|
||||
}
|
||||
},
|
||||
"tx": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "1"
|
||||
},
|
||||
"Destination": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147614720,
|
||||
"LastLedgerSequence": 11234996,
|
||||
"Paths": [
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "1.208084432885738"
|
||||
},
|
||||
"Sequence": 361,
|
||||
"SigningPubKey": "02AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D3",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3044022010E0D6884B36694342958C4872D7BADB825F36E6972757870665DD49580949A30220475F4CEA2904D23148AF51F194973AC73BDB986DA94BD9DEF51A5BBB9D742610",
|
||||
"hash": "F1E35F73FC81BE1599FBEE184F39AC4168E4C181C7ED000137E9E3C62E18D8C6",
|
||||
"inLedger": 11234994,
|
||||
"ledger_index": 11234994
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
},
|
||||
"Payment": {
|
||||
"binary": {
|
||||
"ledger_index": 11234797,
|
||||
"meta": "201C00000003F8E51100612500AA666C55BDB03864DA53C51FE3981DAE091A72289F732FC8A5F3D16F74E7D2036246FA8D5653539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03E6240000016862400000C7C1B0917EE1E7220000000024000001692D0000001662400000C7C1B0629E8114E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E51100722500A0DB72559926ED5C3974070FCA9B3566B7FBF3BCB7C29FCD8A4435781A4AAAE5778576E5565A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DEE66294CE22EC649AF7B70000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E722000200003700000000000000433800000000000000006294CDB50C7C41DBBA0000000000000000000000004A5059000000000000000000000000000000000000000000000000016680000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD46780000000000000000000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337E1E1E511006F2500AB6CF9556E81745BB5DA1EB60C3FDB988EC5CDFE55AD493482F39A54A6AB66E149DB364B566CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BBE664D584488DA40C79F90000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D5038D7EA4C6800000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1E1E72200020000240000DFA82A1C51809E33000000000000000034000000000000062D50103B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F964D5844871834DEC610000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD465D4E3860923E65C0000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1811488F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500A9FF9E5567550A7B0E398944B5528F678BCCA8A53C1356AF9C4FC8EE863B1CC83965C61A56785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26E662940AA87BEE53800000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E7220002000037000000000000027D38000000000000000062940E35FA931A00000000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D503E871B540C0000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6AE1E1E51100722500AB689E55ADE928FA078F53F269317B4FD8BF46C8953D381573BB80231BAC2EB3196DD74A567A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0E66295451D7C249ADC4000000000000000000000000055534400000000000000000000000000000000000000000000000001E1E722002200003700000000000002883800000000000000006295451D79CF5DCB400000000000000000000000005553440000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D167D5438D7EA4C68000000000000000000000000000555344000000000088F647BBEC01AE19BE070B8B91063D14CE77F523E1E1E51100722500AB4C9D55ECABF9CF633CF8FA6578A2C6430B3B9BA9611B8A31BC1730D222A6DD413B0CF156ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACFE662D5C3F427B811675E0000000000000000000000004A505900000000000000000000000000000000000000000000000001E1E7220011000020123B9ACA0037000000000000000038000000000000004662D5C3F42A882475860000000000000000000000004A50590000000000000000000000000000000000000000000000000166D5CAA87BEE5380000000000000000000000000004A5059000000000088F647BBEC01AE19BE070B8B91063D14CE77F5236780000000000000000000000000000000000000004A50590000000000E5C92828261DBAAC933B6309C6F5C72AF020AFD4E1E1F1031000",
|
||||
"tx_blob": "12000022800200002400000168201B00AB6DEF61D4038D7EA4C680000000000000000000000000005553440000000000625E2F1F09A0D769E05C04FAA64F0D2013306C6A684000000000002EE069D491C37937E080000000000000000000000000004A50590000000000E81DCB25DAA1DDEFF45145D334C56F12EA63C337732102AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D37446304402204529AC13FDE2AF411F83DFCCCA1A41534C36A73EC56C00B822EF36B037F8D146022013A1EBC759497D9BB352263C50B49A3E8BD83FA174F6F66B1F095E820026E3588114E81DCB25DAA1DDEFF45145D334C56F12EA63C3378314625E2F1F09A0D769E05C04FAA64F0D2013306C6A011201E5C92828261DBAAC933B6309C6F5C72AF020AFD43000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD41000000000000000000000000000000000000000003000000000000000000000000055534400000000000A20B3C85F482532A9578DBB3950B85CA06594D1010A20B3C85F482532A9578DBB3950B85CA06594D1FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4100000000000000000000000000000000000000000300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD3FF01E5C92828261DBAAC933B6309C6F5C72AF020AFD4300000000000000000000000005553440000000000DD39C650A96EDA48334E70CC4A85B8B2E8502CD301DD39C650A96EDA48334E70CC4A85B8B2E8502CD300",
|
||||
"validated": true
|
||||
},
|
||||
"parsed": {
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Balance": "857948054174",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 22,
|
||||
"Sequence": 361
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "53539B9154C83B7D657103C27ABCA0EF1AD3674F6D0B341F20710FC50EC4DC03",
|
||||
"PreviousFields": {
|
||||
"Balance": "857948066174",
|
||||
"Sequence": 360
|
||||
},
|
||||
"PreviousTxnID": "BDB03864DA53C51FE3981DAE091A72289F732FC8A5F3D16F74E7D2036246FA8D",
|
||||
"PreviousTxnLgrSeq": 11167340
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-38.5823992616441"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000043"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "5A9CDBCBDB64CD58DCD79A352E749EE48D6ACCE258F580F01FE326B31EB023DE",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-39.79048369452983"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "9926ED5C3974070FCA9B3566B7FBF3BCB7C29FCD8A4435781A4AAAE5778576E5",
|
||||
"PreviousTxnLgrSeq": 10541938
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"BookDirectory": "3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E5704488DA40C79F9",
|
||||
"BookNode": "0000000000000000",
|
||||
"Expiration": 475103390,
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "000000000000062D",
|
||||
"Sequence": 57256,
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "99.98998"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12055.52278269025"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "6CD06C01787F1F75688E5C4CE84E83B73ADC1647EC0A2761D553DA776564D1BB",
|
||||
"PreviousFields": {
|
||||
"TakerGets": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "100"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "12056.73086712313"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "6E81745BB5DA1EB60C3FDB988EC5CDFE55AD493482F39A54A6AB66E149DB364B",
|
||||
"PreviousTxnLgrSeq": 11234553
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.04"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "110"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000027D"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "785D84438CD44D7BD8234721BC77022E2BE590E38F9AB73C6E3FBC190524EF26",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.03"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "67550A7B0E398944B5528F678BCCA8A53C1356AF9C4FC8EE863B1CC83965C61A",
|
||||
"PreviousTxnLgrSeq": 11141022
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1439.783890832192"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "1000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0000000000000288"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "7A12DF691E1E8039D53278D20D7CDC88D2C585DDBC4A769CD377CD8FF5C7E6A0",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1439.793910832192"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "ADE928FA078F53F269317B4FD8BF46C8953D381573BB80231BAC2EB3196DD74A",
|
||||
"PreviousTxnLgrSeq": 11233438
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111288.8440026502"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000046",
|
||||
"LowLimit": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rDVBvAQScXrGRGnzrxRrcJPeNLeLeUTAqE",
|
||||
"value": "300000"
|
||||
},
|
||||
"LowNode": "0000000000000000",
|
||||
"LowQualityIn": 1000000000
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "ADB3988C0EF801FF788E40AFA5EA28FBF5C6943C65F4651DDA411881E7FBBACF",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "JPY",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "111287.6359182174"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "ECABF9CF633CF8FA6578A2C6430B3B9BA9611B8A31BC1730D222A6DD413B0CF1",
|
||||
"PreviousTxnLgrSeq": 11226269
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 3,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01"
|
||||
}
|
||||
},
|
||||
"tx": {
|
||||
"Account": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"value": "0.01"
|
||||
},
|
||||
"Destination": "r9y3sFjvdnTMJff1j8k2dodJkwgtghpf1o",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147614720,
|
||||
"LastLedgerSequence": 11234799,
|
||||
"Paths": [
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "XRP",
|
||||
"type": 16,
|
||||
"type_hex": "0000000000000010"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rMAz5ZnK73nyNUL4foAvaxdreczCkG3vA6",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 48,
|
||||
"type_hex": "0000000000000030"
|
||||
},
|
||||
{
|
||||
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"type": 1,
|
||||
"type_hex": "0000000000000001"
|
||||
}
|
||||
]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "JPY",
|
||||
"issuer": "r4wKTbb8AX5kEhXDvHDvhunDqsLZnXGfL9",
|
||||
"value": "5"
|
||||
},
|
||||
"Sequence": 360,
|
||||
"SigningPubKey": "02AC2A11C997C04EC6A4139E6189111F90E89D05F9A9DDC3E2CA459CEA89C539D3",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "304402204529AC13FDE2AF411F83DFCCCA1A41534C36A73EC56C00B822EF36B037F8D146022013A1EBC759497D9BB352263C50B49A3E8BD83FA174F6F66B1F095E820026E358",
|
||||
"hash": "D6405F3E92213763D9AA7270C0CC940864EFEB7CC6A95723E9BC4F33486994A7",
|
||||
"inLedger": 11234797,
|
||||
"ledger_index": 11234797
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
}
|
||||
95
test/fixtures/binary-ledger-data.json
vendored
Normal file
95
test/fixtures/binary-ledger-data.json
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"RippleState": {
|
||||
"binary": {
|
||||
"data": "110072220002000025000B657837000000000000003B3800000000000000005587591A63051645F37B85D1FBA55EE69B1C96BFF16904F5C99F03FB93D42D03756280000000000000000000000000000000000000004254430000000000000000000000000000000000000000000000000166800000000000000000000000000000000000000042544300000000000A20B3C85F482532A9578DBB3950B85CA06594D167D4C38D7EA4C680000000000000000000000000004254430000000000C795FDF8A637BCAAEDAD1C434033506236C82A2D",
|
||||
"index": "000103996A3BAD918657F86E12A67D693E8FC8A814DA4B958A244B5F14D93E58"
|
||||
},
|
||||
"parsed": {
|
||||
"Balance": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rKUK9omZqVEnraCipKNFb5q4tuNTeqEDZS",
|
||||
"value": "10"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000003B",
|
||||
"PreviousTxnID": "87591A63051645F37B85D1FBA55EE69B1C96BFF16904F5C99F03FB93D42D0375",
|
||||
"PreviousTxnLgrSeq": 746872,
|
||||
"index": "000103996A3BAD918657F86E12A67D693E8FC8A814DA4B958A244B5F14D93E58"
|
||||
}
|
||||
},
|
||||
"AccountRoot": {
|
||||
"binary": {
|
||||
"data": "1100612200000000240000000125000DA4192D0000000055CA2EADCF53FEEFE2FF6B47D683A1E33413BC876C7C87669618365C91BD12A42262400000003B9ACA008114D018AF490EB4E476D735159CDEA798B6AF670FF7",
|
||||
"index": "0002D81201E576CF3E0120E2CC35C03E08E22452F498B8C874CD1DF9D3DC305B"
|
||||
},
|
||||
"parsed": {
|
||||
"Account": "rKyK3pQtCTMz6nt6Yxtx8vgju6hLyLWpwh",
|
||||
"Balance": "1000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"OwnerCount": 0,
|
||||
"PreviousTxnID": "CA2EADCF53FEEFE2FF6B47D683A1E33413BC876C7C87669618365C91BD12A422",
|
||||
"PreviousTxnLgrSeq": 893977,
|
||||
"Sequence": 1,
|
||||
"index": "0002D81201E576CF3E0120E2CC35C03E08E22452F498B8C874CD1DF9D3DC305B"
|
||||
}
|
||||
},
|
||||
"Offer": {
|
||||
"binary": {
|
||||
"data": "11006F2200000000240002A44625000F26213300000000000000003400000000000000C0555CCD6C8CD4E7BB1E508F05B831A9B4B634E02862435D5E3E3EEF3AB1690331395010FE4D53B02BC5D46DE095166E0667A0F3797F8A782F8A203B570EBC4086D53E0064D5459C5A55C77D00000000000000000000000000494C53000000000092D705968936C419CE614BF264B5EEB1CEA47FF465D48D871095D18000000000000000000000000000425443000000000092D705968936C419CE614BF264B5EEB1CEA47FF481141C40DA3AAC605E30B6CC5891EA6CDDFA0C996CE8",
|
||||
"index": "002B4106648895A68068DF34FC55AAD9BC1DC135FD737A318C582D706EA505A1"
|
||||
},
|
||||
"parsed": {
|
||||
"Account": "rs2PcQ9HX8afGGPsvUxEmTsrKs5D34kwwK",
|
||||
"BookDirectory": "FE4D53B02BC5D46DE095166E0667A0F3797F8A782F8A203B570EBC4086D53E00",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "00000000000000C0",
|
||||
"PreviousTxnID": "5CCD6C8CD4E7BB1E508F05B831A9B4B634E02862435D5E3E3EEF3AB169033139",
|
||||
"PreviousTxnLgrSeq": 992801,
|
||||
"Sequence": 173126,
|
||||
"TakerGets": {
|
||||
"currency": "BTC",
|
||||
"issuer": "rNPRNzBB92BVpAhhZr4iXDTveCgV5Pofm9",
|
||||
"value": "3.80768"
|
||||
},
|
||||
"TakerPays": {
|
||||
"currency": "ILS",
|
||||
"issuer": "rNPRNzBB92BVpAhhZr4iXDTveCgV5Pofm9",
|
||||
"value": "1579.28668368"
|
||||
},
|
||||
"index": "002B4106648895A68068DF34FC55AAD9BC1DC135FD737A318C582D706EA505A1"
|
||||
}
|
||||
},
|
||||
"DirectoryNode": {
|
||||
"binary": {
|
||||
"data": "110064220000000058001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF18214D5A7C190E367A150A2E4A04DE62E08766B8B48C2011360FE8118802AF3344FDC1DEB95D12F8E7C548928C19FEFE8CF7BD14D28E8F0E9EA3B70BB091D385EB6AFF31C52F05498BB70268FC4BEEDDC6B86770A85D74CEA71E676F574B44A1030EBA09A9A29C939550FAF2849171B3422EB521365F9052D00",
|
||||
"index": "001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF1"
|
||||
},
|
||||
"parsed": {
|
||||
"Flags": 0,
|
||||
"Indexes": [
|
||||
"FE8118802AF3344FDC1DEB95D12F8E7C548928C19FEFE8CF7BD14D28E8F0E9EA",
|
||||
"3B70BB091D385EB6AFF31C52F05498BB70268FC4BEEDDC6B86770A85D74CEA71",
|
||||
"E676F574B44A1030EBA09A9A29C939550FAF2849171B3422EB521365F9052D00"
|
||||
],
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"Owner": "rL76tmsh1Pgy57B4KMqjqWL7mGhwG24xgv",
|
||||
"RootIndex": "001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF1",
|
||||
"index": "001E3B28ABD08E399095EABC6C493E84BFA47B1A6474C04D5289E767A404AEF1"
|
||||
}
|
||||
}
|
||||
}
|
||||
1228
test/fixtures/binary-transaction.json
vendored
Normal file
1228
test/fixtures/binary-transaction.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
303
test/fixtures/metadata-with-hex-accounts.json
vendored
Normal file
303
test/fixtures/metadata-with-hex-accounts.json
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rNGySgyyEdRJ6MKmzsZwyhhVeFKdENRGQ6",
|
||||
"BookDirectory": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FC79E1600",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 131072,
|
||||
"OwnerNode": "0000000000000031",
|
||||
"PreviousTxnID": "83CA9AB231B0B4DA8ACF6305A6D7B00AB83404A1FDB8F8BCF7108EB87E0A8196",
|
||||
"PreviousTxnLgrSeq": 10555009,
|
||||
"Sequence": 12370,
|
||||
"TakerGets": "44978350398",
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "1056.990784602728"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "0496450E3F46368FB011B8B524605A906C0854441D30420457A81EA89BE649BE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rabVnHuo1eq747GbnLDAJfE9GpsGwcL9Hy",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rGa3Tb6vaMVU5RQMjxk4nsMGSArbu8epGG",
|
||||
"value": "5"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "2DECFAC23B77D5AEA6116C15F5C6D4669EBAEE9E7EE050A40FE2B1E47B6A9419",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "3"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "6F35AD78AA196389D15F4BAF054122070506633C1506EF16A48877E2593CCE2D",
|
||||
"PreviousTxnLgrSeq": 10555014
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1228.52678703286"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rabVnHuo1eq747GbnLDAJfE9GpsGwcL9Hy",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "0000000000000076",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rPofp4ruTavGuFnb9AYN2vRPBFxHB7RRsH",
|
||||
"value": "50000"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "4AB2FFDEE65E025AAB54305A161C80D32082574BB0502311F29227089C696388",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1225.52678703286"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "65C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4C",
|
||||
"PreviousTxnLgrSeq": 10554856
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "rP5VvumKn5qqn4RYTMGipmPE9965ARVQNT",
|
||||
"RootIndex": "65E53030C59CD541BB6A8B631F13FA9BBF6F6E28B63D41AA363F23313B34B094"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "65E53030C59CD541BB6A8B631F13FA9BBF6F6E28B63D41AA363F23313B34B094"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rNGySgyyEdRJ6MKmzsZwyhhVeFKdENRGQ6",
|
||||
"Balance": "335297994919",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 12,
|
||||
"Sequence": 12379
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "6ACA1AAB7CD8877EA63E0C282A37FC212AD24640743F019AC2DD8674E003B741",
|
||||
"PreviousFields": {
|
||||
"OwnerCount": 13
|
||||
},
|
||||
"PreviousTxnID": "83CA9AB231B0B4DA8ACF6305A6D7B00AB83404A1FDB8F8BCF7108EB87E0A8196",
|
||||
"PreviousTxnLgrSeq": 10555009
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-15.68270575272517"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rGa3Tb6vaMVU5RQMjxk4nsMGSArbu8epGG",
|
||||
"value": "5000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "000000000000004A"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-12.68270575272517"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "6F35AD78AA196389D15F4BAF054122070506633C1506EF16A48877E2593CCE2D",
|
||||
"PreviousTxnLgrSeq": 10555014
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"IndexPrevious": "000000000000002C",
|
||||
"Owner": "rNGySgyyEdRJ6MKmzsZwyhhVeFKdENRGQ6",
|
||||
"RootIndex": "A93C6B313E260AC7C7734DF44F4461075E2C937C936C2B81DA2C9F69D4A0B0F2"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "8D8FB3359BBA810ED5C5894088F2415E322811181ADCC5BB087E829207DFBBEB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rP5VvumKn5qqn4RYTMGipmPE9965ARVQNT",
|
||||
"Balance": "25116082528",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 5,
|
||||
"Sequence": 2197
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "8F55B7E947241AD38FD6D47374BF8E7CA7DF177C8B79712B4CAC5E91FD5023FF",
|
||||
"PreviousFields": {
|
||||
"OwnerCount": 6
|
||||
},
|
||||
"PreviousTxnID": "0327747C391C678CA2AC46F422E1E8D307A41E9C0ED5DB2677B51CEBE41BD243",
|
||||
"PreviousTxnLgrSeq": 10554892
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rauAjp7gUp8xqHnPFDSo72Nc6aMx2k9yDk",
|
||||
"Balance": "233929959",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 14,
|
||||
"Sequence": 31927
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "A27BB98F7C9D32F404B364622645F80480F87C8A91BB13CA9F6E569144C2A5A8",
|
||||
"PreviousFields": {
|
||||
"Balance": "233941959",
|
||||
"Sequence": 31926
|
||||
},
|
||||
"PreviousTxnID": "65C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4C",
|
||||
"PreviousTxnLgrSeq": 10554856
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4D08594FC79E1600",
|
||||
"Flags": 0,
|
||||
"RootIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FC79E1600",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "0520B3C85F482532A9578DBB3950B85CA03594D1"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FC79E1600"
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4D08594FE7353EDE",
|
||||
"Flags": 0,
|
||||
"RootIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FE7353EDE",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerPaysIssuer": "0520B3C85F482532A9578DBB3950B85CA03594D1"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FE7353EDE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-2818.268620725051"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rauAjp7gUp8xqHnPFDSo72Nc6aMx2k9yDk",
|
||||
"value": "50000"
|
||||
},
|
||||
"HighNode": "0000000000000000",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "00000000000001B0"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "FAD28E839AF29C6CCB8DA6DC71510A5BF8A9C34062C128071C7D22E2469B8288",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-2821.274620725051"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "65C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4C",
|
||||
"PreviousTxnLgrSeq": 10554856
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rP5VvumKn5qqn4RYTMGipmPE9965ARVQNT",
|
||||
"BookDirectory": "DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4D08594FE7353EDE",
|
||||
"BookNode": "0000000000000000",
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "0327747C391C678CA2AC46F422E1E8D307A41E9C0ED5DB2677B51CEBE41BD243",
|
||||
"PreviousTxnLgrSeq": 10554892,
|
||||
"Sequence": 2196,
|
||||
"TakerGets": "4255320000",
|
||||
"TakerPays": {
|
||||
"currency": "USD",
|
||||
"issuer": "rQ3qJZwtzi4Zo3nWbmX9gwCke6S8jmHRCn",
|
||||
"value": "100"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "FB2E442ED1A5BCA1E237BA133807AE17AED1A7E4B9F404906308ADB01A57609D"
|
||||
}
|
||||
}
|
||||
],
|
||||
"DeliveredAmount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rabVnHuo1eq747GbnLDAJfE9GpsGwcL9Hy",
|
||||
"value": "3"
|
||||
},
|
||||
"TransactionIndex": 5,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
}
|
||||
123
test/fixtures/payment-iou.json
vendored
Normal file
123
test/fixtures/payment-iou.json
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"engine_result": "tesSUCCESS",
|
||||
"engine_result_code": 0,
|
||||
"engine_result_message": "The transaction was applied.",
|
||||
"ledger_hash": "F3F1416BF2E813396AB01FAA38E9F1023AC4D2368D94B0D52B2BC603CEEC01C3",
|
||||
"ledger_index": 10459371,
|
||||
"status": "closed",
|
||||
"type": "transaction",
|
||||
"validated": true,
|
||||
"metadata": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1.525330905250352"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "00000000000001E8",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc",
|
||||
"value": "1000000000"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "2F323020B4288ACD4066CC64C89DAD2E4D5DFC2D44571942A51C005BF79D6E25",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "1.535330905250352"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "DC061E6F47B1B6E9A496A31B1AF87194B4CB24B2EBF8A59F35E31E12509238BD",
|
||||
"PreviousTxnLgrSeq": 10459364
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0.02"
|
||||
},
|
||||
"Flags": 1114112,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0"
|
||||
},
|
||||
"HighNode": "00000000000001E8",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K",
|
||||
"value": "1000000000"
|
||||
},
|
||||
"LowNode": "0000000000000000"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "AAE13AF5192EFBFD49A8EEE5869595563FEB73228C0B38FED9CC3D20EE74F399",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0.01"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "DC061E6F47B1B6E9A496A31B1AF87194B4CB24B2EBF8A59F35E31E12509238BD",
|
||||
"PreviousTxnLgrSeq": 10459364
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc",
|
||||
"Balance": "239555992",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 38
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "E9A39B0BA8703D5FFD05D9EAD01EE6C0E7A15CF33C2C6B7269107BD2BD535818",
|
||||
"PreviousFields": {
|
||||
"Balance": "239567992",
|
||||
"Sequence": 37
|
||||
},
|
||||
"PreviousTxnID": "DC061E6F47B1B6E9A496A31B1AF87194B4CB24B2EBF8A59F35E31E12509238BD",
|
||||
"PreviousTxnLgrSeq": 10459364
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 2,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"tx_json": {
|
||||
"Account": "rKmBGxocj9Abgy25J51Mk1iqFzW9aVF9Tc",
|
||||
"Amount": {
|
||||
"currency": "USD",
|
||||
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
"value": "0.01"
|
||||
},
|
||||
"Destination": "rLDYrujdKUfVx28T9vRDAbyJ7G2WVXKo4K",
|
||||
"Fee": "12000",
|
||||
"Flags": 2147483648,
|
||||
"LastLedgerSequence": 10459379,
|
||||
"Sequence": 37,
|
||||
"SigningPubKey": "03F16A52EBDCA6EBF5D99828E1E6918C64D45E6F136476A8F4757512FE553D18F0",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "3044022031D6AB55CDFD17E06DA0BAD6D6B7DC9B5CA8FFF50405F2FCD3ED8D3893B1835E02200524CC1E7D70AE3F00C9F94405C55EE179C363F534905168AE8B5BA01CF568A0",
|
||||
"date": 471644150,
|
||||
"hash": "34671C179737CC89E0F8BBAA83C313885ED1733488FC0F3088BAE16A3D9A5B1B"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Seed = utils.load_module('seed').Seed;
|
||||
var config = require('./testutils').get_config();
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
describe('KeyPair', function() {
|
||||
it('can generate an address', function () {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
|
||||
var utils = require('./testutils');
|
||||
var Ledger = utils.load_module('ledger').Ledger;
|
||||
var config = require('./testutils').get_config();
|
||||
var Ledger = require('ripple-lib').Ledger;
|
||||
|
||||
/**
|
||||
* @param ledger_index {Number}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
var assert = require('assert');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var Message = require('../src/js/ripple/message').Message;
|
||||
var Seed = require('../src/js/ripple/seed').Seed;
|
||||
var Remote = require('../src/js/ripple/remote').Remote;
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
var Message = require('ripple-lib').Message;
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
|
||||
describe('Message', function(){
|
||||
|
||||
|
||||
37
test/metadata-test.js
Normal file
37
test/metadata-test.js
Normal file
@@ -0,0 +1,37 @@
|
||||
var assert = require('assert');
|
||||
var Meta = require('ripple-lib').Meta;
|
||||
|
||||
describe('Meta', function() {
|
||||
var meta = new Meta(require('./fixtures/payment-iou.json').metadata);
|
||||
|
||||
function callback(el, idx, ary) {
|
||||
assert.strictEqual(meta.nodes[idx],el);
|
||||
}
|
||||
|
||||
it('forEach', function() {
|
||||
meta.forEach(callback);
|
||||
});
|
||||
|
||||
it('map', function() {
|
||||
meta.map(callback);
|
||||
});
|
||||
|
||||
it('filter', function() {
|
||||
meta.filter(callback);
|
||||
});
|
||||
|
||||
it('every', function() {
|
||||
meta.every(callback);
|
||||
});
|
||||
|
||||
it('some', function() {
|
||||
meta.some(callback);
|
||||
});
|
||||
|
||||
it('reduce', function() {
|
||||
meta.reduce(function(prev,curr,idx,ary) {
|
||||
assert.strictEqual(meta.nodes[idx], curr);
|
||||
}, []);
|
||||
});
|
||||
|
||||
});
|
||||
1
test/node_modules/ripple-lib
generated
vendored
Symbolic link
1
test/node_modules/ripple-lib
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../../src/js/ripple/
|
||||
@@ -1,9 +1,8 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Currency = utils.load_module('currency').Currency;
|
||||
var Amount = utils.load_module('amount').Amount;
|
||||
var Meta = utils.load_module('meta').Meta;
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Currency = require('ripple-lib').Currency;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var Meta = require('ripple-lib').Meta;
|
||||
|
||||
describe('OrderBook', function() {
|
||||
it('toJSON', function() {
|
||||
@@ -338,6 +337,7 @@ describe('OrderBook', function() {
|
||||
});
|
||||
|
||||
var offer = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: {
|
||||
value: '100',
|
||||
currency: 'BTC',
|
||||
@@ -349,6 +349,7 @@ describe('OrderBook', function() {
|
||||
book.setFundedAmount(offer, '100.1234');
|
||||
|
||||
var expected = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: offer.TakerGets,
|
||||
TakerPays: offer.TakerPays,
|
||||
is_fully_funded: true,
|
||||
@@ -368,6 +369,7 @@ describe('OrderBook', function() {
|
||||
});
|
||||
|
||||
var offer = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: {
|
||||
value: '100',
|
||||
currency: 'BTC',
|
||||
@@ -379,6 +381,7 @@ describe('OrderBook', function() {
|
||||
book.setFundedAmount(offer, '99');
|
||||
|
||||
var expected = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: offer.TakerGets,
|
||||
TakerPays: offer.TakerPays,
|
||||
is_fully_funded: false,
|
||||
@@ -398,6 +401,7 @@ describe('OrderBook', function() {
|
||||
});
|
||||
|
||||
var offer = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: '100',
|
||||
TakerPays: {
|
||||
value: '123.456',
|
||||
@@ -409,6 +413,7 @@ describe('OrderBook', function() {
|
||||
book.setFundedAmount(offer, '100.1');
|
||||
|
||||
var expected = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: offer.TakerGets,
|
||||
TakerPays: offer.TakerPays,
|
||||
is_fully_funded: true,
|
||||
@@ -428,6 +433,7 @@ describe('OrderBook', function() {
|
||||
});
|
||||
|
||||
var offer = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: '100',
|
||||
TakerPays: {
|
||||
value: '123.456',
|
||||
@@ -439,6 +445,7 @@ describe('OrderBook', function() {
|
||||
book.setFundedAmount(offer, '99');
|
||||
|
||||
var expected = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: offer.TakerGets,
|
||||
TakerPays: offer.TakerPays,
|
||||
is_fully_funded: false,
|
||||
@@ -458,6 +465,7 @@ describe('OrderBook', function() {
|
||||
});
|
||||
|
||||
var offer = {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: {
|
||||
value: '100',
|
||||
currency: 'BTC',
|
||||
@@ -469,6 +477,7 @@ describe('OrderBook', function() {
|
||||
book.setFundedAmount(offer, '0');
|
||||
|
||||
assert.deepEqual(offer, {
|
||||
Account: 'rrrrrrrrrrrrrrrrrrrrrhoLvTp',
|
||||
TakerGets: offer.TakerGets,
|
||||
TakerPays: offer.TakerPays,
|
||||
is_fully_funded: false,
|
||||
@@ -1451,6 +1460,56 @@ describe('OrderBook', function() {
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
quality: '498.6116758238228'
|
||||
},
|
||||
{
|
||||
Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29356,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
quality: '498.6116758238228'
|
||||
},
|
||||
{
|
||||
Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29354,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
quality: '498.6116758238228'
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -1534,10 +1593,258 @@ describe('OrderBook', function() {
|
||||
is_fully_funded: true,
|
||||
taker_gets_funded: '0.2',
|
||||
taker_pays_funded: '99.72233516476456'
|
||||
}
|
||||
},
|
||||
{ Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29356,
|
||||
TakerGets: { currency: 'BTC',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
is_fully_funded: false,
|
||||
taker_gets_funded: '0.9484660776278363',
|
||||
taker_pays_funded: '94.58325208561269' },
|
||||
{ Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: {
|
||||
currency: 'BTC',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '0.5'
|
||||
},
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '0.950363009783092',
|
||||
is_fully_funded: false,
|
||||
taker_gets_funded: '0.9484660776278363',
|
||||
taker_pays_funded: '94.58325208561269'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
book.on('model', function(model) {
|
||||
assert.deepEqual(model, expected);
|
||||
assert.strictEqual(book._synchronized, true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Request offers -- native currency', function(done) {
|
||||
var remote = new Remote();
|
||||
|
||||
var offers = {
|
||||
offers: [
|
||||
{
|
||||
Account: 'rGCHV41NxoK7wHQJhmao2RqjWZvBrTUhW1',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000000',
|
||||
Sequence: 195,
|
||||
TakerGets: '1000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '56.06639660617357'
|
||||
},
|
||||
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||
owner_funds: '600'
|
||||
},
|
||||
{
|
||||
Account: 'raudnGKfTK23YKfnS7ixejHrqGERTYNFXk',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '4000',
|
||||
},
|
||||
{
|
||||
Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29356,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '3900',
|
||||
},
|
||||
{
|
||||
Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||
PreviousTxnLgrSeq: 8342469,
|
||||
Sequence: 29354,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
quality: '498.6116758238228'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var expected = [
|
||||
{
|
||||
Account: 'rGCHV41NxoK7wHQJhmao2RqjWZvBrTUhW1',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||
BookNode: '0000000000000000',
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000000',
|
||||
Sequence: 195,
|
||||
TakerGets: '1000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '56.06639660617357'
|
||||
},
|
||||
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||
owner_funds: '600',
|
||||
is_fully_funded: false,
|
||||
taker_gets_funded: '600',
|
||||
taker_pays_funded: '33.63983796370414'
|
||||
},
|
||||
{
|
||||
Account: 'raudnGKfTK23YKfnS7ixejHrqGERTYNFXk',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '4000',
|
||||
is_fully_funded: true,
|
||||
taker_gets_funded: '2000',
|
||||
taker_pays_funded: '99.72233516476456'
|
||||
},
|
||||
{
|
||||
Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131072,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29356,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
owner_funds: '3900',
|
||||
is_fully_funded: false,
|
||||
taker_gets_funded: '3900',
|
||||
taker_pays_funded: '97.22927678564545'
|
||||
},
|
||||
{
|
||||
Account: 'rwBG69mujDoD5yQfL3Sf7Yuh7rUNYdxe9Y',
|
||||
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||
BookNode: '0000000000000000',
|
||||
Expiration: 461498565,
|
||||
Flags: 131078,
|
||||
LedgerEntryType: 'Offer',
|
||||
OwnerNode: '0000000000000144',
|
||||
Sequence: 29354,
|
||||
TakerGets: '2000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
value: '99.72233516476456'
|
||||
},
|
||||
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||
is_fully_funded: false,
|
||||
taker_gets_funded: '3900',
|
||||
taker_pays_funded: '97.22927678564545'
|
||||
}
|
||||
]
|
||||
|
||||
remote.request = function(request) {
|
||||
switch (request.message.command) {
|
||||
case 'book_offers':
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'book_offers',
|
||||
id: void(0),
|
||||
taker_gets: {
|
||||
currency: '0000000000000000000000000000000000000000',
|
||||
},
|
||||
taker_pays: {
|
||||
currency: '0000000000000000000000005553440000000000',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
},
|
||||
taker: 'rrrrrrrrrrrrrrrrrrrrBZbvji'
|
||||
});
|
||||
|
||||
setImmediate(function() {
|
||||
request.emit('success', offers);
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
var book = remote.createOrderBook({
|
||||
currency_gets: 'XRP',
|
||||
currency_pays: 'USD',
|
||||
issuer_pays: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B'
|
||||
});
|
||||
|
||||
book.on('model', function(model) {
|
||||
assert.deepEqual(model, expected);
|
||||
assert.strictEqual(book._synchronized, true);
|
||||
|
||||
78
test/rangeset-test.js
Normal file
78
test/rangeset-test.js
Normal file
@@ -0,0 +1,78 @@
|
||||
var assert = require('assert');
|
||||
var RangeSet = require('ripple-lib').RangeSet;
|
||||
|
||||
describe('RangeSet', function() {
|
||||
it('add()', function() {
|
||||
var r = new RangeSet();
|
||||
|
||||
r.add('4-5');
|
||||
r.add('7-10');
|
||||
r.add('1-2');
|
||||
r.add('3');
|
||||
|
||||
assert.deepEqual(r._ranges, [
|
||||
{ start: 1, end: 2 },
|
||||
{ start: 3, end: 3 },
|
||||
{ start: 4, end: 5 },
|
||||
{ start: 7, end: 10 }
|
||||
]);
|
||||
});
|
||||
|
||||
it('add() -- malformed range', function() {
|
||||
var r = new RangeSet();
|
||||
|
||||
assert.throws(function() {
|
||||
r.add(null);
|
||||
});
|
||||
assert.throws(function() {
|
||||
r.add(void(0));
|
||||
});
|
||||
assert.throws(function() {
|
||||
r.add('a');
|
||||
});
|
||||
assert.throws(function() {
|
||||
r.add('2-1');
|
||||
});
|
||||
});
|
||||
|
||||
it('contains()', function() {
|
||||
var r = new RangeSet();
|
||||
|
||||
r.add('32570-11005146');
|
||||
r.add('11005147');
|
||||
|
||||
assert.strictEqual(r.contains(1), false);
|
||||
assert.strictEqual(r.contains(32569), false);
|
||||
assert.strictEqual(r.contains(32570), true);
|
||||
assert.strictEqual(r.contains('32570'), true);
|
||||
assert.strictEqual(r.contains(50000), true);
|
||||
assert.strictEqual(r.contains(11005146), true);
|
||||
assert.strictEqual(r.contains(11005147), true);
|
||||
assert.strictEqual(r.contains(11005148), false);
|
||||
assert.strictEqual(r.contains(12000000), false);
|
||||
});
|
||||
|
||||
it('contains() -- invalid ledger', function() {
|
||||
var r = new RangeSet();
|
||||
|
||||
assert.throws(function() {
|
||||
r.contains(null);
|
||||
});
|
||||
assert.throws(function() {
|
||||
r.contains(void(0));
|
||||
});
|
||||
assert.throws(function() {
|
||||
r.contains('a');
|
||||
});
|
||||
});
|
||||
|
||||
it('reset()', function() {
|
||||
var r = new RangeSet();
|
||||
|
||||
r.add('4-5');
|
||||
r.add('7-10');
|
||||
r.reset();
|
||||
|
||||
assert.deepEqual(r._ranges, [ ]);
|
||||
});
|
||||
});
|
||||
@@ -1,18 +1,18 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Server = utils.load_module('server').Server;
|
||||
var Request = utils.load_module('request').Request;
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Server = require('ripple-lib').Server;
|
||||
var Request = require('ripple-lib').Request;
|
||||
var UInt160 = require('ripple-lib').UInt160;
|
||||
var Currency = require('ripple-lib').Currency;
|
||||
|
||||
var options, remote, callback, database, tx;
|
||||
|
||||
var ADDRESS = 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS';
|
||||
var PEER_ADDRESS = 'rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX';
|
||||
var LEDGER_INDEX = 9592219;
|
||||
var LEDGER_HASH = 'B4FD84A73DBD8F0DA9E320D137176EBFED969691DC0AAC7882B76B595A0841AE';
|
||||
var PAGING_MARKER = '29F992CC252056BF690107D1E8F2D9FBAFF29FF107B62B1D1F4E4E11ADF2CC73';
|
||||
|
||||
var ADDRESS = 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS';
|
||||
var PEER_ADDRESS = 'rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX';
|
||||
var LEDGER_INDEX = 9592219;
|
||||
var LEDGER_HASH = 'B4FD84A73DBD8F0DA9E320D137176EBFED969691DC0AAC7882B76B595A0841AE';
|
||||
var PAGING_MARKER = '29F992CC252056BF690107D1E8F2D9FBAFF29FF107B62B1D1F4E4E11ADF2CC73';
|
||||
var TRANSACTION_HASH = '14576FFD5D59FFA73CAA90547BE4DE09926AAB59E981306C32CCE04408CBF8EA';
|
||||
|
||||
describe('Remote', function () {
|
||||
beforeEach(function () {
|
||||
@@ -79,28 +79,28 @@ describe('Remote', function () {
|
||||
it('remote server initialization - url object - invalid host', function() {
|
||||
assert.throws(
|
||||
function() {
|
||||
var remote = new Remote({
|
||||
servers: [ { host: '+', port: 443, secure: true } ]
|
||||
});
|
||||
}, Error);
|
||||
var remote = new Remote({
|
||||
servers: [ { host: '+', port: 443, secure: true } ]
|
||||
});
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it('remote server initialization - url object - invalid port', function() {
|
||||
assert.throws(
|
||||
function() {
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: null, secure: true } ]
|
||||
});
|
||||
}, TypeError);
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: null, secure: true } ]
|
||||
});
|
||||
}, TypeError);
|
||||
});
|
||||
|
||||
it('remote server initialization - url object - port out of range', function() {
|
||||
assert.throws(
|
||||
function() {
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 65537, secure: true } ]
|
||||
});
|
||||
}, Error);
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 65537, secure: true } ]
|
||||
});
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it('remote server initialization - url string', function() {
|
||||
@@ -124,30 +124,30 @@ describe('Remote', function () {
|
||||
it('remote server initialization - url string - invalid host', function() {
|
||||
assert.throws(
|
||||
function() {
|
||||
var remote = new Remote({
|
||||
servers: [ 'ws://+:443' ]
|
||||
});
|
||||
}, Error
|
||||
var remote = new Remote({
|
||||
servers: [ 'ws://+:443' ]
|
||||
});
|
||||
}, Error
|
||||
);
|
||||
});
|
||||
|
||||
it('remote server initialization - url string - invalid port', function() {
|
||||
assert.throws(
|
||||
function() {
|
||||
var remote = new Remote({
|
||||
servers: [ 'ws://s-west.ripple.com:null' ]
|
||||
});
|
||||
}, Error
|
||||
var remote = new Remote({
|
||||
servers: [ 'ws://s-west.ripple.com:null' ]
|
||||
});
|
||||
}, Error
|
||||
);
|
||||
});
|
||||
|
||||
it('remote server initialization - url string - port out of range', function() {
|
||||
assert.throws(
|
||||
function() {
|
||||
var remote = new Remote({
|
||||
servers: [ 'ws://s-west.ripple.com:65537:' ]
|
||||
});
|
||||
}, Error
|
||||
var remote = new Remote({
|
||||
servers: [ 'ws://s-west.ripple.com:65537:' ]
|
||||
});
|
||||
}, Error
|
||||
);
|
||||
});
|
||||
|
||||
@@ -179,6 +179,584 @@ describe('Remote', function () {
|
||||
assert.strictEqual((new Remote()).max_fee, 1e6);
|
||||
});
|
||||
|
||||
it('pagingAccountRequest', function() {
|
||||
var request = Remote.accountRequest('account_lines', {account: ADDRESS});
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS
|
||||
});
|
||||
});
|
||||
|
||||
it('pagingAccountRequest - limit', function() {
|
||||
var request = Remote.accountRequest('account_lines', {account: ADDRESS, limit: 100});
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
limit: 100
|
||||
});
|
||||
});
|
||||
|
||||
it('pagingAccountRequest - limit, marker', function() {
|
||||
var request = Remote.accountRequest('account_lines', {account: ADDRESS, limit: 100, marker: PAGING_MARKER, ledger: 9592219});
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
limit: 100,
|
||||
marker: PAGING_MARKER,
|
||||
ledger_index: 9592219
|
||||
});
|
||||
|
||||
assert(!request.requested);
|
||||
});
|
||||
|
||||
it('accountRequest - limit min', function() {
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 0}).message.limit, 0);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: -1}).message.limit, 0);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: -1e9}).message.limit, 0);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: -1e24}).message.limit, 0);
|
||||
});
|
||||
|
||||
it('accountRequest - limit max', function() {
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e9}).message.limit, 1e9);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e9+1}).message.limit, 1e9);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e10}).message.limit, 1e9);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e24}).message.limit, 1e9);
|
||||
});
|
||||
|
||||
it('accountRequest - a valid ledger is required when using a marker', function() {
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:'validated'})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:NaN})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:LEDGER_HASH.substr(0,63)})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:LEDGER_HASH+'F'})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
});
|
||||
|
||||
it('requestAccountLines, account and callback', function() {
|
||||
function callback() {}
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountLines(
|
||||
{account: ADDRESS},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestAccountLines, ledger, peer', function() {
|
||||
function callback() {}
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountLines(
|
||||
{
|
||||
account: ADDRESS,
|
||||
ledger: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestAccountLines, ledger, peer, limit and marker', function() {
|
||||
function callback() {}
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountLines(
|
||||
{
|
||||
account: ADDRESS,
|
||||
ledger: LEDGER_INDEX,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 200,
|
||||
marker: PAGING_MARKER
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
ledger_index: LEDGER_INDEX,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 200,
|
||||
marker: PAGING_MARKER
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestAccountOffers, ledger, peer, limit and marker', function() {
|
||||
function callback() {}
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountOffers(
|
||||
{
|
||||
account: ADDRESS,
|
||||
ledger: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 32,
|
||||
marker: PAGING_MARKER
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_offers',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 32,
|
||||
marker: PAGING_MARKER
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestBookOffers, ledger', function() {
|
||||
function callback() {}
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestBookOffers(
|
||||
{
|
||||
gets: {
|
||||
currency: 'USD',
|
||||
issuer: ADDRESS
|
||||
},
|
||||
pays: {
|
||||
currency: 'XRP'
|
||||
},
|
||||
ledger: LEDGER_HASH
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'book_offers',
|
||||
id: undefined,
|
||||
taker_gets: {
|
||||
currency: Currency.from_human('USD').to_hex(),
|
||||
issuer: ADDRESS
|
||||
},
|
||||
taker_pays: {
|
||||
currency: '0000000000000000000000000000000000000000'
|
||||
},
|
||||
taker: UInt160.ACCOUNT_ONE,
|
||||
ledger_hash: LEDGER_HASH
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestBookOffers, ledger and limit', function() {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestBookOffers(
|
||||
{
|
||||
gets: {
|
||||
currency: 'USD',
|
||||
issuer: ADDRESS
|
||||
},
|
||||
pays: {
|
||||
currency: 'XRP'
|
||||
},
|
||||
ledger: LEDGER_HASH,
|
||||
limit: 10
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'book_offers',
|
||||
id: undefined,
|
||||
taker_gets: {
|
||||
currency: Currency.from_human('USD').to_hex(),
|
||||
issuer: ADDRESS
|
||||
},
|
||||
taker_pays: {
|
||||
currency: Currency.from_human('XRP').to_hex()
|
||||
},
|
||||
taker: UInt160.ACCOUNT_ONE,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
limit: 10
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestAccountTransactions', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountTransactions(
|
||||
{
|
||||
account: UInt160.ACCOUNT_ONE,
|
||||
min_ledger: -1,
|
||||
max_ledger: -1,
|
||||
limit: 5,
|
||||
forward: true,
|
||||
marker: PAGING_MARKER
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_tx',
|
||||
id: undefined,
|
||||
account: UInt160.ACCOUNT_ONE,
|
||||
ledger_index_min: -1,
|
||||
ledger_index_max: -1,
|
||||
binary: true,
|
||||
forward: true,
|
||||
limit: 5,
|
||||
marker: PAGING_MARKER
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestAccountTransactions - binary false', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountTransactions(
|
||||
{
|
||||
binary: false
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_tx',
|
||||
id: undefined,
|
||||
binary: false
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestTransaction', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestTransaction(
|
||||
{
|
||||
hash: TRANSACTION_HASH
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'tx',
|
||||
id: undefined,
|
||||
binary: true,
|
||||
transaction: TRANSACTION_HASH
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestTransaction - hash', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestTransaction(TRANSACTION_HASH, callback);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'tx',
|
||||
id: undefined,
|
||||
binary: true,
|
||||
transaction: TRANSACTION_HASH
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestTransaction - binary false', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestTransaction(
|
||||
{
|
||||
hash: TRANSACTION_HASH,
|
||||
binary: false
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'tx',
|
||||
id: undefined,
|
||||
binary: false,
|
||||
transaction: TRANSACTION_HASH
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestLedgerData', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestLedgerData(
|
||||
{
|
||||
ledger: LEDGER_HASH,
|
||||
limit: 5
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'ledger_data',
|
||||
id: undefined,
|
||||
binary: true,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
limit: 5
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestLedgerData - ledger index', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestLedgerData(
|
||||
{
|
||||
ledger: LEDGER_INDEX,
|
||||
limit: 5,
|
||||
binary: false
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'ledger_data',
|
||||
id: undefined,
|
||||
binary: false,
|
||||
ledger_index: LEDGER_INDEX,
|
||||
limit: 5,
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it ('requestLedgerData - binary false', function () {
|
||||
function callback() {}
|
||||
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestLedgerData(
|
||||
{
|
||||
ledger: LEDGER_HASH,
|
||||
limit: 5,
|
||||
binary: false
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'ledger_data',
|
||||
id: undefined,
|
||||
binary: false,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
limit: 5,
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('create remote and get pending transactions', function() {
|
||||
before(function() {
|
||||
tx = [{
|
||||
tx_json: {
|
||||
Account : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
Amount : {
|
||||
currency : "LTC",
|
||||
issuer : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
value : "9.985"
|
||||
},
|
||||
Destination : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
Fee : "15",
|
||||
Flags : 0,
|
||||
Paths : [
|
||||
[
|
||||
{
|
||||
account : "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
currency : "USD",
|
||||
issuer : "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
type : 49,
|
||||
type_hex : "0000000000000031"
|
||||
},
|
||||
{
|
||||
currency : "LTC",
|
||||
issuer : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX",
|
||||
type : 48,
|
||||
type_hex : "0000000000000030"
|
||||
},
|
||||
{
|
||||
account : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX",
|
||||
currency : "LTC",
|
||||
issuer : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX",
|
||||
type : 49,
|
||||
type_hex : "0000000000000031"
|
||||
}
|
||||
]
|
||||
],
|
||||
SendMax : {
|
||||
currency : "USD",
|
||||
issuer : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
value : "30.30993068"
|
||||
},
|
||||
Sequence : 415,
|
||||
SigningPubKey : "02854B06CE8F3E65323F89260E9E19B33DA3E01B30EA4CA172612DE77973FAC58A",
|
||||
TransactionType : "Payment",
|
||||
TxnSignature : "304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E"
|
||||
},
|
||||
clientID: '48631',
|
||||
state: 'pending',
|
||||
submitIndex: 1,
|
||||
submittedIDs: ["304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E"],
|
||||
secret: 'mysecret'
|
||||
}];
|
||||
database = {
|
||||
getPendingTransactions: function(callback) {
|
||||
callback(null, tx);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should set transaction members correct ', function(done) {
|
||||
remote = new Remote(options);
|
||||
remote.storage = database;
|
||||
remote.transaction = function() {
|
||||
return {
|
||||
clientID: function(id) {
|
||||
if (typeof id === 'string') {
|
||||
this._clientID = id;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
submit: function() {
|
||||
assert.deepEqual(this._clientID, tx[0].clientID);
|
||||
assert.deepEqual(this.submittedIDs,[tx[0].tx_json.TxnSignature]);
|
||||
assert.equal(this.submitIndex, tx[0].submitIndex);
|
||||
assert.equal(this.secret, tx[0].secret);
|
||||
done();
|
||||
|
||||
},
|
||||
parseJson: function(json) {}
|
||||
}
|
||||
};
|
||||
remote.getPendingTransactions();
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
it('Remote.parseBinaryAccountTransaction()', function() {
|
||||
var binaryAccountTransaction = require('./fixtures/binary-account-transaction.json');
|
||||
|
||||
var parsed = Remote.parseBinaryAccountTransaction(binaryAccountTransaction.OfferCreate.binary);
|
||||
assert.deepEqual(parsed, binaryAccountTransaction.OfferCreate.parsed);
|
||||
|
||||
var parsedPartialPayment = Remote.parseBinaryAccountTransaction(binaryAccountTransaction.PartialPayment.binary);
|
||||
assert.deepEqual(parsedPartialPayment, binaryAccountTransaction.PartialPayment.parsed);
|
||||
|
||||
var parsedPayment = Remote.parseBinaryAccountTransaction(binaryAccountTransaction.Payment.binary);
|
||||
assert.deepEqual(parsedPayment, binaryAccountTransaction.Payment.parsed);
|
||||
});
|
||||
|
||||
it('Remote.parseBinaryTransaction()', function () {
|
||||
var binaryTransaction = require('./fixtures/binary-transaction.json');
|
||||
|
||||
var parsedSourceTag = Remote.parseBinaryTransaction(binaryTransaction.PaymentWithSourceTag.binary);
|
||||
assert.deepEqual(parsedSourceTag, binaryTransaction.PaymentWithSourceTag.parsed);
|
||||
|
||||
var parsedMemosAndPaths = Remote.parseBinaryTransaction(binaryTransaction.PaymentWithMemosAndPaths.binary);
|
||||
assert.deepEqual(parsedMemosAndPaths, binaryTransaction.PaymentWithMemosAndPaths.parsed);
|
||||
|
||||
var parsedPartialPayment = Remote.parseBinaryTransaction(binaryTransaction.PartialPayment.binary);
|
||||
assert.deepEqual(parsedPartialPayment, binaryTransaction.PartialPayment.parsed);
|
||||
|
||||
var parsedOfferCreate = Remote.parseBinaryTransaction(binaryTransaction.OfferCreate.binary);
|
||||
assert.deepEqual(parsedOfferCreate, binaryTransaction.OfferCreate.parsed);
|
||||
|
||||
var parsedPartialPaymentWithXRPDelieveredAmount = Remote.parseBinaryTransaction(binaryTransaction.PartialPaymentWithXRPDeliveredAmount.binary);
|
||||
assert.deepEqual(parsedPartialPaymentWithXRPDelieveredAmount, binaryTransaction.PartialPaymentWithXRPDeliveredAmount.parsed);
|
||||
});
|
||||
|
||||
it('Remote.parseBinaryLedgerData()', function () {
|
||||
var binaryLedgerData = require('./fixtures/binary-ledger-data.json');
|
||||
|
||||
var parsedAccountRoot = Remote.parseBinaryLedgerData(binaryLedgerData.AccountRoot.binary);
|
||||
assert.deepEqual(parsedAccountRoot, binaryLedgerData.AccountRoot.parsed);
|
||||
|
||||
var parsedOffer = Remote.parseBinaryLedgerData(binaryLedgerData.Offer.binary);
|
||||
assert.deepEqual(parsedOffer, binaryLedgerData.Offer.parsed);
|
||||
|
||||
var parsedDirectoryNode = Remote.parseBinaryLedgerData(binaryLedgerData.DirectoryNode.binary);
|
||||
assert.deepEqual(parsedDirectoryNode, binaryLedgerData.DirectoryNode.parsed);
|
||||
|
||||
var parsedRippleState = Remote.parseBinaryLedgerData(binaryLedgerData.RippleState.binary);
|
||||
assert.deepEqual(parsedRippleState, binaryLedgerData.RippleState.parsed);
|
||||
});
|
||||
|
||||
describe('request constructors', function () {
|
||||
beforeEach(function () {
|
||||
callback = function () {}
|
||||
@@ -263,263 +841,33 @@ describe('Remote', function () {
|
||||
assert.strictEqual(request.message.account_root, ADDRESS);
|
||||
assert.strictEqual(request.message.ledger_index, 'validated');
|
||||
});
|
||||
});
|
||||
|
||||
it('pagingAccountRequest', function() {
|
||||
var request = Remote.accountRequest('account_lines', {account: ADDRESS});
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS
|
||||
it('request offer with ledger index', function() {
|
||||
var request = remote.requestOffer({account: ADDRESS, ledger: LEDGER_INDEX, sequence: 5});
|
||||
assert.strictEqual(request.message.command, 'ledger_entry');
|
||||
assert.strictEqual(request.message.offer.account, ADDRESS);
|
||||
assert.strictEqual(request.message.offer.seq, 5);
|
||||
assert.strictEqual(request.message.ledger_index, LEDGER_INDEX);
|
||||
});
|
||||
it('request offer with ledger hash', function() {
|
||||
var request = remote.requestOffer({account: ADDRESS, ledger: LEDGER_HASH, sequence: 5});
|
||||
assert.strictEqual(request.message.command, 'ledger_entry');
|
||||
assert.strictEqual(request.message.offer.account, ADDRESS);
|
||||
assert.strictEqual(request.message.offer.seq, 5);
|
||||
assert.strictEqual(request.message.ledger_hash, LEDGER_HASH);
|
||||
});
|
||||
it('request account balance with ledger identifier', function() {
|
||||
var request = remote.requestOffer({account: ADDRESS, ledger: 'validated', sequence: 5});
|
||||
assert.strictEqual(request.message.command, 'ledger_entry');
|
||||
assert.strictEqual(request.message.offer.account, ADDRESS);
|
||||
assert.strictEqual(request.message.offer.seq, 5);
|
||||
assert.strictEqual(request.message.ledger_index, 'validated');
|
||||
});
|
||||
it('request account balance with offer index', function() {
|
||||
var request = remote.requestOffer({ index: TRANSACTION_HASH, ledger: LEDGER_INDEX});
|
||||
assert.strictEqual(request.message.command, 'ledger_entry');
|
||||
assert.strictEqual(request.message.offer, TRANSACTION_HASH);
|
||||
assert.strictEqual(request.message.ledger_index, LEDGER_INDEX);
|
||||
});
|
||||
});
|
||||
|
||||
it('pagingAccountRequest - limit', function() {
|
||||
var request = Remote.accountRequest('account_lines', {account: ADDRESS, limit: 100});
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
limit: 100
|
||||
});
|
||||
});
|
||||
|
||||
it('pagingAccountRequest - limit, marker', function() {
|
||||
var request = Remote.accountRequest('account_lines', {account: ADDRESS, limit: 100, marker: PAGING_MARKER, ledger: 9592219});
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
limit: 100,
|
||||
marker: PAGING_MARKER,
|
||||
ledger_index: 9592219
|
||||
});
|
||||
|
||||
assert(!request.requested);
|
||||
});
|
||||
|
||||
it('accountRequest - limit min', function() {
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 0}).message.limit, 0);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: -1}).message.limit, 0);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: -1e9}).message.limit, 0);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: -1e24}).message.limit, 0);
|
||||
});
|
||||
|
||||
it('accountRequest - limit max', function() {
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e9}).message.limit, 1e9);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e9+1}).message.limit, 1e9);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e10}).message.limit, 1e9);
|
||||
assert.strictEqual(Remote.accountRequest('account_lines', {account: ADDRESS, limit: 1e24}).message.limit, 1e9);
|
||||
});
|
||||
|
||||
it('accountRequest - a valid ledger is required when using a marker', function() {
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:'validated'})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:NaN})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:LEDGER_HASH.substr(0,63)})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
|
||||
assert.throws(function() {
|
||||
Remote.accountRequest('account_lines', {account: ADDRESS, marker: PAGING_MARKER, ledger:LEDGER_HASH+'F'})
|
||||
},'A ledger_index or ledger_hash must be provided when using a marker');
|
||||
});
|
||||
|
||||
it('requestAccountLines, account and callback', function() {
|
||||
var callback = function() {};
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountLines(
|
||||
{account: ADDRESS},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestAccountLines, ledger, peer', function() {
|
||||
var callback = function() {};
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountLines(
|
||||
{
|
||||
account: ADDRESS,
|
||||
ledger: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestAccountLines, ledger, peer, limit and marker', function() {
|
||||
var callback = function() {};
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountLines(
|
||||
{
|
||||
account: ADDRESS,
|
||||
ledger: LEDGER_INDEX,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 200,
|
||||
marker: PAGING_MARKER
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_lines',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
ledger_index: LEDGER_INDEX,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 200,
|
||||
marker: PAGING_MARKER
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('requestAccountOffers, ledger, peer, limit and marker', function() {
|
||||
var callback = function() {};
|
||||
var remote = new Remote({
|
||||
servers: [ { host: 's-west.ripple.com', port: 443, secure: true } ]
|
||||
});
|
||||
var request = remote.requestAccountOffers(
|
||||
{
|
||||
account: ADDRESS,
|
||||
ledger: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 32,
|
||||
marker: PAGING_MARKER
|
||||
},
|
||||
callback
|
||||
);
|
||||
|
||||
assert.deepEqual(request.message, {
|
||||
command: 'account_offers',
|
||||
id: undefined,
|
||||
account: ADDRESS,
|
||||
ledger_hash: LEDGER_HASH,
|
||||
peer: PEER_ADDRESS,
|
||||
limit: 32,
|
||||
marker: PAGING_MARKER
|
||||
});
|
||||
|
||||
assert(request.requested);
|
||||
});
|
||||
|
||||
it('create remote and get pending transactions', function() {
|
||||
before(function() {
|
||||
tx = [{
|
||||
tx_json: {
|
||||
Account : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
Amount : {
|
||||
currency : "LTC",
|
||||
issuer : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
value : "9.985"
|
||||
},
|
||||
Destination : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
Fee : "15",
|
||||
Flags : 0,
|
||||
Paths : [
|
||||
[
|
||||
{
|
||||
account : "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
currency : "USD",
|
||||
issuer : "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||
type : 49,
|
||||
type_hex : "0000000000000031"
|
||||
},
|
||||
{
|
||||
currency : "LTC",
|
||||
issuer : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX",
|
||||
type : 48,
|
||||
type_hex : "0000000000000030"
|
||||
},
|
||||
{
|
||||
account : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX",
|
||||
currency : "LTC",
|
||||
issuer : "rfYv1TXnwgDDK4WQNbFALykYuEBnrR4pDX",
|
||||
type : 49,
|
||||
type_hex : "0000000000000031"
|
||||
}
|
||||
]
|
||||
],
|
||||
SendMax : {
|
||||
currency : "USD",
|
||||
issuer : "r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS",
|
||||
value : "30.30993068"
|
||||
},
|
||||
Sequence : 415,
|
||||
SigningPubKey : "02854B06CE8F3E65323F89260E9E19B33DA3E01B30EA4CA172612DE77973FAC58A",
|
||||
TransactionType : "Payment",
|
||||
TxnSignature : "304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E"
|
||||
},
|
||||
clientID: '48631',
|
||||
state: 'pending',
|
||||
submitIndex: 1,
|
||||
submittedIDs: ["304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E"],
|
||||
secret: 'mysecret'
|
||||
}];
|
||||
database = {
|
||||
getPendingTransactions: function(callback) {
|
||||
callback(null, tx);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should set transaction members correct ', function(done) {
|
||||
remote = new Remote(options);
|
||||
remote.storage = database;
|
||||
remote.transaction = function() {
|
||||
return {
|
||||
clientID: function(id) {
|
||||
if (typeof id === 'string') {
|
||||
this._clientID = id;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
submit: function() {
|
||||
assert.deepEqual(this._clientID, tx[0].clientID);
|
||||
assert.deepEqual(this.submittedIDs,[tx[0].tx_json.TxnSignature]);
|
||||
assert.equal(this.submitIndex, tx[0].submitIndex);
|
||||
assert.equal(this.secret, tx[0].secret);
|
||||
done();
|
||||
|
||||
},
|
||||
parseJson: function(json) {}
|
||||
}
|
||||
};
|
||||
remote.getPendingTransactions();
|
||||
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Request = utils.load_module('request').Request;
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Server = utils.load_module('server').Server;
|
||||
var Currency = utils.load_module('currency').Currency;
|
||||
var Request = require('ripple-lib').Request;
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Server = require('ripple-lib').Server;
|
||||
var Currency = require('ripple-lib').Currency;
|
||||
var RippleError = require('ripple-lib').RippleError;
|
||||
|
||||
function makeServer(url) {
|
||||
var server = new Server(new process.EventEmitter(), url);
|
||||
@@ -56,7 +56,7 @@ describe('Request', function() {
|
||||
request.request();
|
||||
});
|
||||
|
||||
it('Broadcast request', function(done) {
|
||||
it('Send request -- filterRequest', function(done) {
|
||||
var servers = [
|
||||
makeServer('wss://localhost:5006'),
|
||||
makeServer('wss://localhost:5007')
|
||||
@@ -64,24 +64,401 @@ describe('Request', function() {
|
||||
|
||||
var requests = 0;
|
||||
|
||||
servers.forEach(function(server, index, arr) {
|
||||
server._request = function(req) {
|
||||
assert(req instanceof Request);
|
||||
assert.strictEqual(typeof req.message, 'object');
|
||||
assert.strictEqual(req.message.command, 'server_info');
|
||||
if (++requests === arr.length) {
|
||||
done();
|
||||
}
|
||||
};
|
||||
});
|
||||
var successResponse = {
|
||||
account_data: {
|
||||
Account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
Balance: '13188802787',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 17,
|
||||
PreviousTxnID: 'C6A2313CD9E34FFA3EB42F82B2B30F7FE12A045F1F4FDDAF006B25D7286536DD',
|
||||
PreviousTxnLgrSeq: 8828020,
|
||||
Sequence: 1406,
|
||||
index: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05'
|
||||
},
|
||||
ledger_current_index: 9022821,
|
||||
validated: false
|
||||
};
|
||||
var errorResponse = {
|
||||
error: 'remoteError',
|
||||
error_message: 'Remote reported an error.',
|
||||
remote: {
|
||||
id: 3,
|
||||
status: 'error',
|
||||
type: 'response',
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
error: 'actNotFound',
|
||||
error_code: 15,
|
||||
error_message: 'Account not found.',
|
||||
ledger_current_index: 9022856,
|
||||
request: {
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
command: 'account_info',
|
||||
id: 3
|
||||
},
|
||||
validated: false
|
||||
}
|
||||
};
|
||||
|
||||
function checkRequest(req) {
|
||||
assert(req instanceof Request);
|
||||
assert.strictEqual(typeof req.message, 'object');
|
||||
assert.strictEqual(req.message.command, 'account_info');
|
||||
};
|
||||
|
||||
servers[0]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
req.emit('error', errorResponse);
|
||||
};
|
||||
|
||||
servers[1]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
setImmediate(function() {
|
||||
req.emit('success', successResponse);
|
||||
});
|
||||
};
|
||||
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
remote._servers = servers;
|
||||
|
||||
var request = new Request(remote, 'server_info');
|
||||
var request = new Request(remote, 'account_info');
|
||||
|
||||
request.broadcast();
|
||||
request.message.account = 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC';
|
||||
|
||||
request.filter(function(res) {
|
||||
return res
|
||||
&& typeof res === 'object'
|
||||
&& !res.hasOwnProperty('error');
|
||||
});
|
||||
|
||||
request.callback(function(err, res) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(requests, 2, 'Failed to broadcast');
|
||||
assert.deepEqual(res, successResponse);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Send request -- filterRequest -- no success', function(done) {
|
||||
var servers = [
|
||||
makeServer('wss://localhost:5006'),
|
||||
makeServer('wss://localhost:5007')
|
||||
];
|
||||
|
||||
var requests = 0;
|
||||
|
||||
var errorResponse = {
|
||||
error: 'remoteError',
|
||||
error_message: 'Remote reported an error.',
|
||||
remote: {
|
||||
id: 3,
|
||||
status: 'error',
|
||||
type: 'response',
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
error: 'actNotFound',
|
||||
error_code: 15,
|
||||
error_message: 'Account not found.',
|
||||
ledger_current_index: 9022856,
|
||||
request: {
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
command: 'account_info',
|
||||
id: 3
|
||||
},
|
||||
validated: false
|
||||
}
|
||||
};
|
||||
|
||||
function checkRequest(req) {
|
||||
assert(req instanceof Request);
|
||||
assert.strictEqual(typeof req.message, 'object');
|
||||
assert.strictEqual(req.message.command, 'account_info');
|
||||
};
|
||||
|
||||
function sendError(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
req.emit('error', errorResponse);
|
||||
};
|
||||
servers[0]._request = sendError;
|
||||
servers[1]._request = sendError;
|
||||
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
remote._servers = servers;
|
||||
|
||||
var request = new Request(remote, 'account_info');
|
||||
|
||||
request.message.account = 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC';
|
||||
|
||||
request.filter(function(res) {
|
||||
return res
|
||||
&& typeof res === 'object'
|
||||
&& !res.hasOwnProperty('error');
|
||||
});
|
||||
|
||||
request.callback(function(err, res) {
|
||||
setImmediate(function() {
|
||||
assert.strictEqual(requests, 2, 'Failed to broadcast');
|
||||
assert.deepEqual(err, new RippleError(errorResponse));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Send request -- filterRequest -- ledger prefilter', function(done) {
|
||||
var servers = [
|
||||
makeServer('wss://localhost:5006'),
|
||||
makeServer('wss://localhost:5007')
|
||||
];
|
||||
|
||||
var requests = 0;
|
||||
|
||||
var successResponse = {
|
||||
account_data: {
|
||||
Account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
Balance: '13188802787',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 17,
|
||||
PreviousTxnID: 'C6A2313CD9E34FFA3EB42F82B2B30F7FE12A045F1F4FDDAF006B25D7286536DD',
|
||||
PreviousTxnLgrSeq: 8828020,
|
||||
Sequence: 1406,
|
||||
index: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05'
|
||||
},
|
||||
ledger_current_index: 9022821,
|
||||
validated: false
|
||||
};
|
||||
|
||||
function checkRequest(req) {
|
||||
assert(req instanceof Request);
|
||||
assert.strictEqual(typeof req.message, 'object');
|
||||
assert.strictEqual(req.message.command, 'account_info');
|
||||
};
|
||||
|
||||
servers[0]._request = function(req) {
|
||||
assert(false, 'Should not request; server does not have ledger');
|
||||
};
|
||||
|
||||
servers[1]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
setImmediate(function() {
|
||||
req.emit('success', successResponse);
|
||||
});
|
||||
};
|
||||
|
||||
servers[0]._ledgerRanges.add('5-6');
|
||||
servers[1]._ledgerRanges.add('1-4');
|
||||
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
remote._servers = servers;
|
||||
|
||||
var request = new Request(remote, 'account_info');
|
||||
request.message.account = 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC';
|
||||
request.selectLedger(4);
|
||||
|
||||
request.filter(function(res) {
|
||||
return res
|
||||
&& typeof res === 'object'
|
||||
&& !res.hasOwnProperty('error');
|
||||
});
|
||||
|
||||
request.callback(function(err, res) {
|
||||
assert.ifError(err);
|
||||
assert.deepEqual(res, successResponse);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Send request -- filterRequest -- server reconnects', function(done) {
|
||||
var servers = [
|
||||
makeServer('wss://localhost:5006'),
|
||||
makeServer('wss://localhost:5007')
|
||||
];
|
||||
|
||||
var requests = 0;
|
||||
|
||||
var successResponse = {
|
||||
account_data: {
|
||||
Account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
Balance: '13188802787',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 17,
|
||||
PreviousTxnID: 'C6A2313CD9E34FFA3EB42F82B2B30F7FE12A045F1F4FDDAF006B25D7286536DD',
|
||||
PreviousTxnLgrSeq: 8828020,
|
||||
Sequence: 1406,
|
||||
index: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05'
|
||||
},
|
||||
ledger_current_index: 9022821,
|
||||
validated: false
|
||||
};
|
||||
var errorResponse = {
|
||||
error: 'remoteError',
|
||||
error_message: 'Remote reported an error.',
|
||||
remote: {
|
||||
id: 3,
|
||||
status: 'error',
|
||||
type: 'response',
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
error: 'actNotFound',
|
||||
error_code: 15,
|
||||
error_message: 'Account not found.',
|
||||
ledger_current_index: 9022856,
|
||||
request: {
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
command: 'account_info',
|
||||
id: 3
|
||||
},
|
||||
validated: false
|
||||
}
|
||||
};
|
||||
|
||||
function checkRequest(req) {
|
||||
assert(req instanceof Request);
|
||||
assert.strictEqual(typeof req.message, 'object');
|
||||
assert.strictEqual(req.message.command, 'account_info');
|
||||
};
|
||||
|
||||
servers[0]._connected = false;
|
||||
servers[0]._shouldConnect = true;
|
||||
servers[0].removeAllListeners('connect');
|
||||
|
||||
servers[0]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
req.emit('success', successResponse);
|
||||
};
|
||||
servers[1]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
|
||||
req.emit('error', errorResponse);
|
||||
|
||||
servers[0]._connected = true;
|
||||
servers[0].emit('connect');
|
||||
};
|
||||
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
remote._servers = servers;
|
||||
|
||||
var request = new Request(remote, 'account_info');
|
||||
|
||||
request.message.account = 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC';
|
||||
|
||||
request.filter(function(res) {
|
||||
return res
|
||||
&& typeof res === 'object'
|
||||
&& !res.hasOwnProperty('error');
|
||||
});
|
||||
|
||||
request.callback(function(err, res) {
|
||||
assert.ifError(err);
|
||||
setImmediate(function() {
|
||||
assert.strictEqual(requests, 2, 'Failed to broadcast');
|
||||
assert.deepEqual(res, successResponse);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Send request -- filterRequest -- server fails to reconnect', function(done) {
|
||||
var servers = [
|
||||
makeServer('wss://localhost:5006'),
|
||||
makeServer('wss://localhost:5007')
|
||||
];
|
||||
|
||||
var requests = 0;
|
||||
|
||||
var successResponse = {
|
||||
account_data: {
|
||||
Account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
Balance: '13188802787',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 17,
|
||||
PreviousTxnID: 'C6A2313CD9E34FFA3EB42F82B2B30F7FE12A045F1F4FDDAF006B25D7286536DD',
|
||||
PreviousTxnLgrSeq: 8828020,
|
||||
Sequence: 1406,
|
||||
index: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05'
|
||||
},
|
||||
ledger_current_index: 9022821,
|
||||
validated: false
|
||||
};
|
||||
var errorResponse = {
|
||||
error: 'remoteError',
|
||||
error_message: 'Remote reported an error.',
|
||||
remote: {
|
||||
id: 3,
|
||||
status: 'error',
|
||||
type: 'response',
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
error: 'actNotFound',
|
||||
error_code: 15,
|
||||
error_message: 'Account not found.',
|
||||
ledger_current_index: 9022856,
|
||||
request: {
|
||||
account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||
command: 'account_info',
|
||||
id: 3
|
||||
},
|
||||
validated: false
|
||||
}
|
||||
};
|
||||
|
||||
function checkRequest(req) {
|
||||
assert(req instanceof Request);
|
||||
assert.strictEqual(typeof req.message, 'object');
|
||||
assert.strictEqual(req.message.command, 'account_info');
|
||||
};
|
||||
|
||||
servers[0]._connected = false;
|
||||
servers[0]._shouldConnect = true;
|
||||
servers[0].removeAllListeners('connect');
|
||||
|
||||
setTimeout(function() {
|
||||
servers[0]._connected = true;
|
||||
servers[0].emit('connect');
|
||||
}, 20);
|
||||
|
||||
servers[0]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
req.emit('success', successResponse);
|
||||
};
|
||||
servers[1]._request = function(req) {
|
||||
++requests;
|
||||
checkRequest(req);
|
||||
req.emit('error', errorResponse);
|
||||
};
|
||||
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
remote._servers = servers;
|
||||
|
||||
var request = new Request(remote, 'account_info');
|
||||
request.setReconnectTimeout(10);
|
||||
request.message.account = 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC';
|
||||
|
||||
request.filter(function(res) {
|
||||
return res
|
||||
&& typeof res === 'object'
|
||||
&& !res.hasOwnProperty('error');
|
||||
});
|
||||
|
||||
request.callback(function(err, res) {
|
||||
setTimeout(function() {
|
||||
// Wait for the request that would emit 'success' to time out
|
||||
assert.deepEqual(err, new RippleError(errorResponse));
|
||||
assert.deepEqual(servers[0].listeners('connect'), [ ]);
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
|
||||
it('Events API', function(done) {
|
||||
@@ -349,6 +726,16 @@ describe('Request', function() {
|
||||
assert.strictEqual(request.message.ledger_hash, void(0));
|
||||
});
|
||||
|
||||
it('Select ledger - index (String)', function() {
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
|
||||
var request = new Request(remote, 'server_info');
|
||||
request.ledgerSelect('7016915');
|
||||
assert.strictEqual(request.message.ledger_index, 7016915);
|
||||
assert.strictEqual(request.message.ledger_hash, void(0));
|
||||
});
|
||||
|
||||
it('Select ledger - hash', function() {
|
||||
var remote = new Remote();
|
||||
remote._connected = true;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Seed = utils.load_module('seed').Seed;
|
||||
var config = require('./testutils').get_config();
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
describe('Seed', function() {
|
||||
it('can generate many addresses', function () {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var utils = require('./testutils');
|
||||
var assert = require('assert');
|
||||
var SerializedObject = utils.load_module('serializedobject').SerializedObject;
|
||||
var sjcl = require('./../src/js/ripple/utils').sjcl;
|
||||
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
|
||||
// Shortcuts
|
||||
var hex = sjcl.codec.hex;
|
||||
@@ -30,10 +29,14 @@ describe('Serialized object', function() {
|
||||
{
|
||||
account: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
currency: 'USD',
|
||||
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV'
|
||||
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||
type: 49,
|
||||
type_hex: "0000000000000031"
|
||||
},
|
||||
{
|
||||
currency: 'XRP'
|
||||
currency: 'XRP',
|
||||
type: 16,
|
||||
type_hex: "0000000000000010"
|
||||
}
|
||||
]],
|
||||
SendMax: {
|
||||
@@ -325,4 +328,4 @@ describe('Serialized object', function() {
|
||||
|
||||
});
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
var utils = require('./testutils');
|
||||
var assert = require('assert');
|
||||
var SerializedObject = utils.load_module('serializedobject').SerializedObject;
|
||||
var types = utils.load_module('serializedtypes');
|
||||
var amountConstants = require('../src/js/ripple/amount').consts;
|
||||
var BigInteger = require('../src/js/jsbn/jsbn').BigInteger;
|
||||
|
||||
var config = require('./testutils').get_config();
|
||||
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||
var types = require('ripple-lib').types;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var BigInteger = require('ripple-lib').jsbn.BigInteger;
|
||||
|
||||
describe('Serialized types', function() {
|
||||
describe('Int8', function() {
|
||||
@@ -553,7 +550,7 @@ describe('Serialized types', function() {
|
||||
});
|
||||
it('Serialize max_value/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||
var so = new SerializedObject();
|
||||
types.Amount.serialize(so, amountConstants.max_value+'/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
types.Amount.serialize(so, Amount.max_value+'/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(so.to_hex(), 'EC6386F26FC0FFFF0000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
|
||||
});
|
||||
it('Parse 1 XRP', function () {
|
||||
@@ -590,7 +587,7 @@ describe('Serialized types', function() {
|
||||
});
|
||||
it('Parse max_value/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||
var so = new SerializedObject('EC6386F26FC0FFFF0000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
|
||||
assert.strictEqual(types.Amount.parse(so).to_text_full(), amountConstants.max_value+'/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
assert.strictEqual(types.Amount.parse(so).to_text_full(), Amount.max_value+'/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -676,7 +673,7 @@ describe('Serialized types', function() {
|
||||
it('Serialize path through XRP', function () {
|
||||
var hex = '31000000000000000000000000000000000000007B00000000000000000000000055534400000000000000000000000000000000000000000000000315FF1000000000000000000000000000000000000000003100000000000000000000000000000000000003DB0000000000000000000000004555520000000000000000000000000000000000000000000000014100';
|
||||
var json = [
|
||||
[ {
|
||||
[{
|
||||
account: "rrrrrrrrrrrrrrrrrrrrNxV3Xza",
|
||||
currency: 'USD',
|
||||
issuer: "rrrrrrrrrrrrrrrrrrrpYnYCNYf"
|
||||
@@ -690,18 +687,39 @@ describe('Serialized types', function() {
|
||||
}]
|
||||
];
|
||||
|
||||
var result_json = [
|
||||
[{
|
||||
account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}],
|
||||
[{
|
||||
currency: 'XRP',
|
||||
type: 16,
|
||||
type_hex: '0000000000000010'
|
||||
}, {
|
||||
account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
|
||||
currency: 'EUR',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}]
|
||||
];
|
||||
|
||||
var so = new SerializedObject();
|
||||
types.PathSet.serialize(so, json);
|
||||
assert.strictEqual(so.to_hex(), hex);
|
||||
|
||||
so = new SerializedObject(hex);
|
||||
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
|
||||
assert.deepEqual(parsed_path, json);
|
||||
assert.deepEqual(parsed_path, result_json);
|
||||
});
|
||||
it('Serialize path through XRP IOUs', function () {
|
||||
var hex = '31000000000000000000000000000000000000007B00000000000000000000000055534400000000000000000000000000000000000000000000000315FF1000000000000000000000000058525000000000003100000000000000000000000000000000000003DB0000000000000000000000004555520000000000000000000000000000000000000000000000014100';
|
||||
var json = [
|
||||
[ {
|
||||
[{
|
||||
account: "rrrrrrrrrrrrrrrrrrrrNxV3Xza",
|
||||
currency: 'USD',
|
||||
issuer: "rrrrrrrrrrrrrrrrrrrpYnYCNYf"
|
||||
@@ -716,13 +734,35 @@ describe('Serialized types', function() {
|
||||
}]
|
||||
];
|
||||
|
||||
var result_json = [
|
||||
[{
|
||||
account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}],
|
||||
[{
|
||||
currency: 'XRP',
|
||||
non_native: true,
|
||||
type: 16,
|
||||
type_hex: '0000000000000010'
|
||||
}, {
|
||||
account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
|
||||
currency: 'EUR',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}]
|
||||
];
|
||||
|
||||
var so = new SerializedObject();
|
||||
types.PathSet.serialize(so, json);
|
||||
assert.strictEqual(so.to_hex(), hex);
|
||||
|
||||
so = new SerializedObject(hex);
|
||||
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
|
||||
assert.deepEqual(parsed_path, json);
|
||||
assert.deepEqual(parsed_path, result_json);
|
||||
});
|
||||
it('Serialize path through XRP IOUs (realistic example)', function () {
|
||||
// Appears in the history
|
||||
@@ -781,13 +821,87 @@ describe('Serialized types', function() {
|
||||
}]
|
||||
];
|
||||
|
||||
var result_json = [
|
||||
[{
|
||||
account: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
currency: 'BTC',
|
||||
issuer: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
account: 'rM1oqKtfh1zgjdAgbFmaRm3btfGBX25xVo',
|
||||
currency: 'BTC',
|
||||
issuer: 'rM1oqKtfh1zgjdAgbFmaRm3btfGBX25xVo',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
currency: 'BTC',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
type: 48,
|
||||
type_hex: '0000000000000030'
|
||||
}],
|
||||
[{
|
||||
account: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
currency: 'BTC',
|
||||
issuer: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
account: 'rM1oqKtfh1zgjdAgbFmaRm3btfGBX25xVo',
|
||||
currency: 'BTC',
|
||||
issuer: 'rM1oqKtfh1zgjdAgbFmaRm3btfGBX25xVo',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
account: 'rpvfJ4mR6QQAeogpXEKnuyGBx8mYCSnYZi',
|
||||
currency: 'BTC',
|
||||
issuer: 'rpvfJ4mR6QQAeogpXEKnuyGBx8mYCSnYZi',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
type: 48,
|
||||
type_hex: '0000000000000030'
|
||||
}],
|
||||
[{
|
||||
account: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
currency: 'BTC',
|
||||
issuer: 'r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
account: 'r3AWbdp2jQLXLywJypdoNwVSvr81xs3uhn',
|
||||
currency: 'BTC',
|
||||
issuer: 'r3AWbdp2jQLXLywJypdoNwVSvr81xs3uhn',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031'
|
||||
}, {
|
||||
currency: 'XRP',
|
||||
non_native: true,
|
||||
type: 16,
|
||||
type_hex: '0000000000000010'
|
||||
}, {
|
||||
currency: 'USD',
|
||||
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
type: 48,
|
||||
type_hex: '0000000000000030'
|
||||
}]
|
||||
];
|
||||
|
||||
var so = new SerializedObject();
|
||||
types.PathSet.serialize(so, json);
|
||||
assert.strictEqual(so.to_hex(), hex);
|
||||
|
||||
so = new SerializedObject(hex);
|
||||
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
|
||||
assert.deepEqual(parsed_path, json);
|
||||
assert.deepEqual(parsed_path, result_json);
|
||||
});
|
||||
it('Parse single empty path [[]]', function () {
|
||||
var so = new SerializedObject('00');
|
||||
@@ -800,13 +914,20 @@ describe('Serialized types', function() {
|
||||
var parsed_path = types.PathSet.parse(so);
|
||||
var comp = [ [ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
||||
currency: 'USD',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf' } ],
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031' } ],
|
||||
[ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
||||
currency: 'BTC',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf' },
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031' },
|
||||
{ account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
|
||||
currency: 'EUR',
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2' } ] ];
|
||||
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2',
|
||||
type: 49,
|
||||
type_hex: '0000000000000031' } ] ];
|
||||
|
||||
assert.deepEqual(SerializedObject.jsonify_structure(parsed_path, ""), comp);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
var assert = require('assert');
|
||||
var ws = require('ws');
|
||||
var utils = require('./testutils');
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Server = utils.load_module('server').Server;
|
||||
var Request = utils.load_module('request').Request;
|
||||
var Transaction = utils.load_module('transaction').Transaction;
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Server = require('ripple-lib').Server;
|
||||
var Request = require('ripple-lib').Request;
|
||||
var Transaction = require('ripple-lib').Transaction;
|
||||
|
||||
describe('Server', function() {
|
||||
it('Server constructor - invalid options', function() {
|
||||
@@ -1132,4 +1131,74 @@ describe('Server', function() {
|
||||
|
||||
server.connect();
|
||||
});
|
||||
|
||||
it('Track ledger ranges', function(done) {
|
||||
var wss = new ws.Server({ port: 5748 });
|
||||
|
||||
wss.once('connection', function(ws) {
|
||||
function sendSubscribe(message) {
|
||||
ws.send(JSON.stringify({
|
||||
id: message.id,
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
fee_base: 10,
|
||||
fee_ref: 10,
|
||||
ledger_hash: '1838539EE12463C36F2C53B079D807C697E3D93A1936B717E565A4A912E11776',
|
||||
ledger_index: 7053695,
|
||||
ledger_time: 455414390,
|
||||
load_base: 256,
|
||||
load_factor: 256,
|
||||
random: 'E56C9154D9BE94D49C581179356C2E084E16D18D74E8B09093F2D61207625E6A',
|
||||
reserve_base: 20000000,
|
||||
reserve_inc: 5000000,
|
||||
server_status: 'full',
|
||||
validated_ledgers: '32570-7053695',
|
||||
pubkey_node: 'n94pSqypSfddzAVj9qoezHyUoetsrMnwgNuBqRJ3WHvM8aMMf7rW',
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
ws.on('message', function(message) {
|
||||
var m = JSON.parse(message);
|
||||
|
||||
switch (m.command) {
|
||||
case 'subscribe':
|
||||
assert.strictEqual(m.command, 'subscribe');
|
||||
assert.deepEqual(m.streams, [ 'ledger', 'server' ]);
|
||||
sendSubscribe(m);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var server = new Server(new Remote(), 'ws://localhost:5748');
|
||||
|
||||
server.once('connect', function() {
|
||||
assert.strictEqual(server.hasLedger(32569), false);
|
||||
assert.strictEqual(server.hasLedger(32570), true);
|
||||
assert.strictEqual(server.hasLedger(7053695), true);
|
||||
assert.strictEqual(server.hasLedger(7053696), false);
|
||||
|
||||
server.emit('message', {
|
||||
type: 'ledgerClosed',
|
||||
fee_base: 10,
|
||||
fee_ref: 10,
|
||||
ledger_hash: 'F29E1F2A2617A88E9DAA14F468B169E6875092ECA0B3B1FA2BE1BC5524DE7CB2',
|
||||
ledger_index: 7053696,
|
||||
ledger_time: 455327690,
|
||||
reserve_base: 20000000,
|
||||
reserve_inc: 5000000,
|
||||
txn_count: 1
|
||||
});
|
||||
|
||||
assert.strictEqual(server.hasLedger(7053696), true);
|
||||
assert.strictEqual(server.hasLedger('F29E1F2A2617A88E9DAA14F468B169E6875092ECA0B3B1FA2BE1BC5524DE7CB2'), true);
|
||||
|
||||
server.once('disconnect', done);
|
||||
wss.close();
|
||||
});
|
||||
|
||||
server.connect();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Seed = utils.load_module('seed').Seed;
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
function _isNaN(n) {
|
||||
return typeof n === 'number' && isNaN(n);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var Seed = require('../src/js/ripple/seed').Seed;
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
var Seed = require('ripple-lib').Seed;
|
||||
|
||||
describe('SJCL ECDSA Canonicalization', function() {
|
||||
describe('canonicalizeSignature', function() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
|
||||
describe('ECDSA signing with recoverable public key', function(){
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
|
||||
describe('SJCL Extramath', function() {
|
||||
describe('setBitM', function() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
|
||||
describe('SJCL Jacobi', function() {
|
||||
it('(15/13) = -1', function () {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var sjcl = require('ripple-lib').sjcl;
|
||||
|
||||
function testExp(vec) {
|
||||
var actual = new sjcl.bn(vec.g).powermodMontgomery(new sjcl.bn(vec.e),
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
var ripple = require('../src/js/ripple');
|
||||
|
||||
exports.get_config = get_config;
|
||||
|
||||
function get_config() {
|
||||
var config = { };
|
||||
try {
|
||||
config = require('./config');
|
||||
} catch(exception) {
|
||||
config = require('./config-example');
|
||||
}
|
||||
return load_config(config);
|
||||
};
|
||||
|
||||
exports.load_config = load_config;
|
||||
|
||||
function load_config(config) {
|
||||
return load_module('config').load(config);
|
||||
};
|
||||
|
||||
exports.load_module = load_module;
|
||||
|
||||
function load_module(name) {
|
||||
if (process.env.RIPPLE_LIB_COV) {
|
||||
return require('../src-cov/js/ripple/' + name)
|
||||
} else if (!ripple.hasOwnProperty(name)) {
|
||||
return require('../src/js/ripple/' + name);
|
||||
} else {
|
||||
return require('../src/js/ripple')[name];
|
||||
}
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var Transaction = utils.load_module('transaction').Transaction;
|
||||
var TransactionQueue = utils.load_module('transactionqueue').TransactionQueue;
|
||||
var Transaction = require('ripple-lib').Transaction;
|
||||
var TransactionQueue = require('ripple-lib').TransactionQueue;
|
||||
|
||||
describe('Transaction queue', function() {
|
||||
it('Push transaction', function() {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
var utils = require('./testutils');
|
||||
var assert = require('assert');
|
||||
var Amount = utils.load_module('amount').Amount;
|
||||
var Transaction = utils.load_module('transaction').Transaction;
|
||||
var TransactionQueue = utils.load_module('transactionqueue').TransactionQueue;
|
||||
var Remote = utils.load_module('remote').Remote;
|
||||
var Server = utils.load_module('server').Server;
|
||||
var Amount = require('ripple-lib').Amount;
|
||||
var Transaction = require('ripple-lib').Transaction;
|
||||
var TransactionQueue = require('ripple-lib').TransactionQueue;
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
var Server = require('ripple-lib').Server;
|
||||
|
||||
var transactionResult = {
|
||||
engine_result: 'tesSUCCESS',
|
||||
@@ -1215,14 +1214,15 @@ describe('Transaction', function() {
|
||||
]);
|
||||
});
|
||||
|
||||
it('Construct AccountSet transaction', function() {
|
||||
var transaction = new Transaction().accountSet('rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm');
|
||||
|
||||
it('Set AccountTxnID', function() {
|
||||
var transaction = new Transaction();
|
||||
assert(transaction instanceof Transaction);
|
||||
|
||||
transaction.accountTxnID('75C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4F');
|
||||
|
||||
assert.deepEqual(transaction.tx_json, {
|
||||
Flags: 0,
|
||||
TransactionType: 'AccountSet',
|
||||
Account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm'
|
||||
AccountTxnID: '75C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4F'
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1239,6 +1239,18 @@ describe('Transaction', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('Construct AccountSet transaction - with AccountTxnID SetFlag', function() {
|
||||
var transaction = new Transaction().accountSet('rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 'asfAccountTxnID');
|
||||
|
||||
assert(transaction instanceof Transaction);
|
||||
assert.deepEqual(transaction.tx_json, {
|
||||
Flags: 0,
|
||||
SetFlag: 5,
|
||||
TransactionType: 'AccountSet',
|
||||
Account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm'
|
||||
});
|
||||
});
|
||||
|
||||
it('Construct AccountSet transaction - params object', function() {
|
||||
var transaction = new Transaction().accountSet({
|
||||
account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var UInt128 = utils.load_module('uint128').UInt128;
|
||||
var config = require('./testutils').get_config();
|
||||
var UInt128 = require('ripple-lib').UInt128;
|
||||
|
||||
describe('UInt', function() {
|
||||
describe('128', function() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
var fs = require('fs');
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils').load_module('utils');
|
||||
var utils = require('ripple-lib').utils;
|
||||
|
||||
describe('Utils', function() {
|
||||
describe('hexToString and stringToHex', function() {
|
||||
|
||||
@@ -1,851 +0,0 @@
|
||||
var assert = require('assert');
|
||||
var RippleTxt = require('../src/js/ripple/rippletxt').RippleTxt;
|
||||
var AuthInfo = require('../src/js/ripple/authinfo').AuthInfo;
|
||||
var VaultClient = require('../src/js/ripple/vaultclient').VaultClient;
|
||||
var Blob = require('../src/js/ripple/blob').Blob;
|
||||
var UInt256 = require('../src/js/ripple/uint256').UInt256;
|
||||
var sjcl = require('../build/sjcl');
|
||||
var nock = require('nock');
|
||||
var online = process.argv.indexOf('--online-blobvault') !== -1 ? true : false;
|
||||
|
||||
var exampleData = {
|
||||
id: 'ef203d3e76552c0592384f909e6f61f1d1f02f61f07643ce015d8b0c9710dd2f',
|
||||
crypt: 'f0cc91a7c1091682c245cd8e13c246cc150b2cf98b17dd6ef092019c99dc9d82',
|
||||
unlock: '3e15fe3218a9c664835a6f585582e14480112110ddbe50e5028d05fc5bd9b5f4',
|
||||
username: 'exampleUser',
|
||||
new_username : 'exampleUser-rename',
|
||||
password: 'pass word',
|
||||
domain: 'staging.ripple.com',
|
||||
masterkey : 'ssize4HrSYZShMWBtK6BhALGEk8VH',
|
||||
email_token : '77825040-9096-4695-9cbc-76720f6a8649',
|
||||
activateLink : 'https://staging.ripple.com/client/#/register/activate/',
|
||||
device_id : "ac1b6f6dbca98190eb9687ba06f0e066",
|
||||
identity_id : "17fddb71-a5c2-44ce-8b50-4b381339d4f2",
|
||||
blob: {
|
||||
url: 'https://id.staging.ripple.com',
|
||||
id: 'ef203d3e76552c0592384f909e6f61f1d1f02f61f07643ce015d8b0c9710dd2f',
|
||||
key: 'f0cc91a7c1091682c245cd8e13c246cc150b2cf98b17dd6ef092019c99dc9d82',
|
||||
data: {
|
||||
auth_secret: 'd0aa918e693080a6a8d0ddc7f4dcf4bc0eecc3c3e3235f16a98661ee9c2e7a58',
|
||||
account_id: 'raVUps4RghLYkVBcpMaRbVKRTTzhesPXd',
|
||||
email: 'example@example.com',
|
||||
contacts: [ ],
|
||||
created: '2014-05-20T23:39:52.538Z',
|
||||
apps: [ ],
|
||||
lastSeenTxDate: 1401925490000,
|
||||
identityVault: { },
|
||||
revision: 2199,
|
||||
encrypted_secret: 'APYqtqvjJk/J324rx2BGGzUiQ3mtmMMhMsbrUmgxb00W2aFVQzCC2mqd58Z17gzeUUcjtjAm'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var rippleTxtRes = "[authinfo_url]\r\nhttps://id.staging.ripple.com/v1/authinfo";
|
||||
|
||||
var authInfoRes = {
|
||||
body : {
|
||||
version: 3,
|
||||
blobvault: 'https://id.staging.ripple.com',
|
||||
pakdf: {
|
||||
modulus: 'c7f1bc1dfb1be82d244aef01228c1409c1988943ca9e21431f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd',
|
||||
alpha: '7283d19e784f48a96062271a5fa6e2c3addf14e6ezf78a4bb61364856d580f13552008d7b9e3b60ebd9555e9f6c7778ec69f976757d206134e54d61ba9d588a7e37a77cf48060522478352d76db000366ef669a1b1ca93c5e3e05bc344afa1e8ccb15d3343da94180dccf590c2c32408c3f3f176c8885e95d988f1565ee9b80c12f72503ab49917792f907bbb9037487b0afed967fefc9ab090164597fcd391c43fab33029b38e66ff4af96cbf6d90a01b891f856ddd3d94e9c9b307fe01e1353a8c30edd5a94a0ebba5fe7161569000ad3b0d3568872d52b6fbdfce987a687e4b346ea702e8986b03b6b1b85536c813e46052a31ed64ec490d3ba38029544aa',
|
||||
url: 'https://auth1.ripple.com/api/sign',
|
||||
exponent: '010001',
|
||||
host: 'auth1.ripple.com'
|
||||
},
|
||||
exists: true,
|
||||
username: 'exampleUser',
|
||||
address: 'raVUps4RghLYkVBcpMaRbVKRTTzhesPXd',
|
||||
emailVerified: true,
|
||||
reserved: false
|
||||
}
|
||||
};
|
||||
|
||||
var authInfoNewUsernameRes = {
|
||||
body : {
|
||||
version: 3,
|
||||
blobvault: 'https://id.staging.ripple.com',
|
||||
pakdf: {
|
||||
modulus: 'c7f1bc1dfb1be82d244aef01228c1409c1988943ca9e21431f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd',
|
||||
alpha: '7283d19e784f48a96062271a5fa6e2c3addf14e6ezf78a4bb61364856d580f13552008d7b9e3b60ebd9555e9f6c7778ec69f976757d206134e54d61ba9d588a7e37a77cf48060522478352d76db000366ef669a1b1ca93c5e3e05bc344afa1e8ccb15d3343da94180dccf590c2c32408c3f3f176c8885e95d988f1565ee9b80c12f72503ab49917792f907bbb9037487b0afed967fefc9ab090164597fcd391c43fab33029b38e66ff4af96cbf6d90a01b891f856ddd3d94e9c9b307fe01e1353a8c30edd5a94a0ebba5fe7161569000ad3b0d3568872d52b6fbdfce987a687e4b346ea702e8986b03b6b1b85536c813e46052a31ed64ec490d3ba38029544aa',
|
||||
url: 'https://auth1.ripple.com/api/sign',
|
||||
exponent: '010001',
|
||||
host: 'auth1.ripple.com'
|
||||
},
|
||||
exists: false,
|
||||
username: exampleData.new_username,
|
||||
emailVerified: false,
|
||||
reserved: false
|
||||
}
|
||||
};
|
||||
|
||||
var signRes = '{"result":"success","signres":"64e9e46618fff0b720b8162e6caa209e046af128b929b766d3be421d3f048ba523453dad42597dcec01f23a5080c16695f6209d39a03668d46b782409e4a53821f70b5e6f7c8fd28eb641c504f9f9b2f378bf2ea7f19950790ac6a8832e2659800f5bb06b735bd450fa47b499fbcebeb3b0fc327619dd2171fa40fb0a41d9bcd69dd29567fa94e9466d4674b908f1cfc43822b38b94534cb37eead183b11b33761a73d78be6ba6f3a53291d4154ca0891fa59da58380e05a1e85b15a24d12406795385bcc5a6360a24ecbf068ff6f02097cd917281972d4895769f3a8668b852ea5d4232050200bcd03934f49ea0693d832980614dff1ead67ca2e0ce9073c25","modulus":"c7f1bc1dfb1be82d244aef01228c1409c198894eca9e21430f1669b4aa3864c9f37f3d51b2b4ba1ab9e80f59d267fda1521e88b05117993175e004543c6e3611242f24432ce8efa3b81f0ff660b4f91c5d52f2511a6f38181a7bf9abeef72db056508bbb4eeb5f65f161dd2d5b439655d2ae7081fcc62fdcb281520911d96700c85cdaf12e7d1f15b55ade867240722425198d4ce39019550c4c8a921fc231d3e94297688c2d77cd68ee8fdeda38b7f9a274701fef23b4eaa6c1a9c15b2d77f37634930386fc20ec291be95aed9956801e1c76601b09c413ad915ff03bfdc0b6b233686ae59e8caf11750b509ab4e57ee09202239baee3d6e392d1640185e1cd","alpha":"7283d19e784f48a96062271a4fa6e2c3addf14e6edf78a4bb61364856d580f13552008d7b9e3b60ebd9555e9f6c7778ec69f976757d206134e54d61ba9d588a7e37a77cf48060522478352d76db000366ef669a1b1ca93c5e3e05bc344afa1e8ccb15d3343da94180dccf590c2c32408c3f3f176c8885e95d988f1565ee9b80c12f72503ab49917792f907bbb9037487b0afed967fefc9ab090164597fcd391c43fab33029b38e66ff4af96cbf6d90a01b891f856ddd3d94e9c9b307fe01e1353a8c30edd5a94a0ebba5fe7161569000ad3b0d3568872d52b6fbdfce987a687e4b346ea702e8986b03b6b1b85536c813e46052a31ed64ec490d3ba38029544aa","exponent":"010001"}';
|
||||
|
||||
var blobRes = {
|
||||
body : {
|
||||
result: 'success',
|
||||
encrypted_secret: 'APYqtqvjJk/J324rx2BGGzUiQ3mtmMMhMsbrUmgxb00W2aFVQzCC2mqd58Z17gzeUUcjtjAm',
|
||||
blob: 'ALXga/k8mgvPpZCY0zJZdaqlptHUBL0E4V/90p4edvb7eCucU2M7aFsHIl3Z3UDu9MdlDnDU42/C+YKL1spkSTPb3rGWr0kXIFmRu8xDAd+OA3Ot7u3OBq0sN2BUHbEc47WiCue84XQHTgBh9tdeiRTqm90LJ7hZ1pD0oqr823YpFguwcC1inxFbSTNxIdWSoC3XCqZtRFM2Y5ALleWhaWKc3OwaFU6yPRcW05IBvTY/7a2SfZyklvXnJh7Bg+vfvz7ms8UCybmBgHlBPY/UqGOdZI6iFGrEQrDMFHgbxwf7bTTiaOM7Su3OsqhM1k90LvQgk3b1olb1VIMZ5J1UuTtOVTpLSsIlzgMvxxdUUyN2zMkeDE3t8kHOThhwWbLG6O+s9F9fktIv4NtoAm0dG9LtkSE1YXajk0qIYr/zrblJy7pEvNv+EzdSr+dpvssmPshgwxoHwvCwae0vL7UTmrCxIWLlHbsbU2uAzgvudJL0WOpX4W+R43U3sgMD2XysKgX783Sa7DLUWCk3Rk9eGp7c3k/XpI0IWvuKzMxID8VzdyMmXP0RE77uUufisBDtwr8gPGzS5kzU3Z/FG/dHJkfBLZdbHOffQTPKO9DKUjztWpx7CTAkN9O21XrdLK1FRAtWFTuvlA66sDYtHRaqglzFjt9DsJk7PAKi1odHeLBmYob/Bs5eK9yNnlLwu3JpHLH/jKxkuxcZ3NEdTm1WPjTdNlvT7kdGAIG9c0vIywEABkQh1kPDOe39h3GRGcUqVWJcMjJmdVDrQH7BBVV+VptCVtMOo1LviaD0MIWMiYdZyGeH5x+FkpAMjKDB3cCUkmxmis8lrDiMlnTZ5Czj+bDPp62Looc7cr2pTR2niFZRosYNgUPx6cAh7tn64RDaa/spAyv0mWyD1qRA8H0sEPmC7m7EPaBIQpODh1NFg/Bxunh+QGSmy9deINB78b9A9zLS6qWljrzg5fMDUN66xRUUKJMSD9+QJePsM4pb60vbnBBtbe04JzY7iOc/CxiT0Px6/1jlSmnY6SCtaFqtDgmQ5MLGTm1tA+aj6caT6FWsXrBboXt3eXRDPHTN+ciKELx7M3dpd4mKVWhBu7nnnVMEu1rSUrmtUStXQHod/C7vVRF2EU1hhTW7ou0hvLn+7xs9B76QeVG7iYFLiZH1qgs+upqnLCnmY3ug9yd9GQ6YwbVL1hbXJLadaOg7qhKst0KXjjjcE4G9AIEyI+UCxGdc/0PNPOCCeYEPshvonCgElGo/fAbaIuSSOFfusiovYffJ0rCkq1RagH0R/llWtUEFEDR5YFVlD3DqK6B22fQK',
|
||||
revision: 2191,
|
||||
email: 'example@example.com',
|
||||
quota: -2975,
|
||||
patches: []
|
||||
}
|
||||
};
|
||||
|
||||
var recoverRes = {
|
||||
body: {
|
||||
encrypted_secret: 'AAd69B9En2OF4O4LsjD+pFNeJHEGIuLh2hbla58zGvN7qU/16bDfy0QlFj8/Gu++AdFwH5U6',
|
||||
revision: 2403,
|
||||
blob_id: 'ef203d3e76552c0592384f909e6f61f1d1f02f61f07643ce015d8b0c9710dd2f',
|
||||
blob: 'AFfW9vuHJ2J5UMnEl4WrVIT9z2d+PPVNNHkqzN64b3pKDQcRPFp8vVEqL9B+YVs/KHhFVFNxxCNyVXwO/yGg4BAslYl8Ioo11IODmOltJmb94oKR/JVyfaY4bDWaOzAoa5N/c9LHpmd0L+9igK1o260MK5OZW4BQ6EG7I+8cYi5uM2CLguiddySu2yTEnyHW47zspWP33y2deh6p5mHtLdii/tmlm7b2rKpzrRVuLN/J09jqilhMxlCEr4X065YZLlQapJ45UWvpifejEw/6Qgl1WngZxwifHa504aR/QYhb1XCNeYbkjQ1MmkTmTef47Al4r/Irzoe//pDbAFA70XXkBUVUMAXWiOxU5V6gHO4yhXbTFEn7922JZlY7PIjo2Q+BxLkozMzuh8MZdoeadqffZX1fOuyTRWfPlqi7vIYgnUyTmThKe2EZv1LsB5ZUaX3KSArKDv1xPTKS0nexGNZoFckwEfVr6B2PGbMx8LPLYEEEmd95kh8NAKN1wkOPuBehLAtbMtcnLpTsotY6diqWdW4V9BSst0KDMTxZVfeesWD7/7ga9hzNvAWO1MN3aAvDCiQVufb44i4Qfu6fLS7+nxtcDCN2PqPHcANcW0cUhUNB50ajzNwRXN8B92CiY0zkS61CzWeooHOslGp0Acau1CJy8iHGyjzbPS4ui8F2h2TbDUuInOoMqiRjXFvRTxA=',
|
||||
encrypted_blobdecrypt_key: 'AA9vUokfQ1WXEOArl2DUwY3cxgXGKj9uNEqrJQzUu0hqXIWRu1V+6l1qqxXKPnm9BNscMpm0BMSbxUz++lfV50c1B4akvrzIBH+MUUgNyyPcHR7JBgjEYt0=',
|
||||
patches: [],
|
||||
result: 'success'
|
||||
}
|
||||
}
|
||||
|
||||
var getProfileRes = {
|
||||
"result":"success",
|
||||
"addresses":[],
|
||||
"attributes":[{
|
||||
"attribute_id":"4034e477-ffc9-48c4-bcbc-058293f081d8",
|
||||
"identity_id":"17fddb71-a5c2-44ce-8b50-4b381339d4f2",
|
||||
"name":"email",
|
||||
"type":"default",
|
||||
"domain":null,
|
||||
"value":"example@example.com",
|
||||
"visibility":"public",
|
||||
"updated":null
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var blob = new Blob();
|
||||
blob.url = exampleData.blob.url;
|
||||
blob.id = exampleData.blob.id;
|
||||
blob.device_id = exampleData.device_id;
|
||||
blob.key = exampleData.blob.key;
|
||||
blob.identity_id = exampleData.blob.identity_id;
|
||||
blob.data = exampleData.blob.data;
|
||||
blob.revision = exampleData.blob.data.revision;
|
||||
|
||||
//must be set for self signed certs
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
while(!sjcl.random.isReady()) {
|
||||
sjcl.random.addEntropy(require('crypto').randomBytes(128).toString('base64')); //add entropy to seed the generator
|
||||
}
|
||||
|
||||
var mockRippleTxt;
|
||||
var mockRippleTxt2;
|
||||
var mockAuthSign;
|
||||
var mockRegister;
|
||||
var mockBlob;
|
||||
var mockRename;
|
||||
var mockUpdate;
|
||||
var mockRecover;
|
||||
var mockVerify;
|
||||
var mockEmail;
|
||||
var mockProfile;
|
||||
var mockDelete;
|
||||
|
||||
if (!online) {
|
||||
mockRippleTxt = nock('https://ripple.com')
|
||||
.get('/ripple.txt')
|
||||
.reply(200, rippleTxtRes, {
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
|
||||
mockRippleTxt2 = nock('https://' + exampleData.domain)
|
||||
.get('/ripple.txt')
|
||||
.reply(200, rippleTxtRes, {
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
|
||||
mockAuthSign = nock('https://auth1.ripple.com')
|
||||
.persist()
|
||||
.post('/api/sign')
|
||||
.reply(200, signRes, {
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
|
||||
mockRegister = nock('https://id.staging.ripple.com');
|
||||
mockRegister.filteringPath(/(v1\/user\?signature(.+))/g, 'register/')
|
||||
.post('/register/')
|
||||
.reply(200, { result: 'error', message: 'User already exists' }, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockDelete = nock('https://id.staging.ripple.com');
|
||||
mockDelete.filteringPath(/(v1\/user\/(.+))/g, 'delete/')
|
||||
.delete('/delete/')
|
||||
.reply(200, { result: 'success' }, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockBlob = nock('https://id.staging.ripple.com');
|
||||
mockBlob.get('/v1/authinfo?domain=' + exampleData.domain + '&username=' + exampleData.username.toLowerCase())
|
||||
.reply(200, JSON.stringify(authInfoRes.body), {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockBlob.get('/v1/authinfo?domain=' + exampleData.domain + '&username=' + exampleData.new_username.toLowerCase())
|
||||
.reply(200, JSON.stringify(authInfoNewUsernameRes.body), {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockBlob.filteringPath(/(blob\/.+)/g, 'blob/')
|
||||
.persist()
|
||||
.get('/v1/blob/')
|
||||
.reply(200, JSON.stringify(blobRes.body), {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockRename = nock('https://id.staging.ripple.com/v1/user/');
|
||||
mockRename.filteringPath(/((.+)\/rename(.+))/g, 'rename/')
|
||||
.post('rename/')
|
||||
.reply(200, {result:'success',message:'rename'}, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockUpdate = nock('https://id.staging.ripple.com/v1/user/');
|
||||
mockUpdate.filteringPath(/((.+)\/updatekeys(.+))/g, 'update/')
|
||||
.post('update/')
|
||||
.reply(200, {result:'success',message:'updateKeys'}, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockRecover = nock('https://id.staging.ripple.com/')
|
||||
mockRecover.filteringPath(/((.+)user\/recov\/(.+))/g, 'recov/')
|
||||
.get('recov/')
|
||||
.reply(200, recoverRes.body, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockVerify = nock('https://id.staging.ripple.com/v1/user/');
|
||||
mockVerify.filteringPath(/((.+)\/verify(.+))/g, 'verify/')
|
||||
.get('verify/')
|
||||
.reply(200, {result:'error', message:'invalid token'}, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
mockEmail = nock('https://id.staging.ripple.com/v1/user');
|
||||
mockEmail.filteringPath(/((.+)\/email(.+))/g, 'email/')
|
||||
.post('email/')
|
||||
.reply(200, {result:'success'}, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
describe('Ripple Txt', function () {
|
||||
it('should get the content of a ripple.txt file from a given domain', function(done) {
|
||||
RippleTxt.get(exampleData.domain, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get currencies from a ripple.txt file for a given domain', function(done) {
|
||||
RippleTxt.getCurrencies(exampleData.domain, function(err, currencies) {
|
||||
assert.ifError(err);
|
||||
assert(Array.isArray(currencies));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should get the domain from a given url', function() {
|
||||
var domain = RippleTxt.extractDomain("http://www.example.com");
|
||||
assert.strictEqual(typeof domain, 'string');
|
||||
});
|
||||
});
|
||||
|
||||
describe('AuthInfo', function() {
|
||||
it('should get auth info', function(done) {
|
||||
AuthInfo.get(exampleData.domain, exampleData.username, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
Object.keys(authInfoRes.body).forEach(function(prop) {
|
||||
assert(resp.hasOwnProperty(prop));
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('VaultClient', function () {
|
||||
var client = new VaultClient(exampleData.domain);
|
||||
|
||||
describe('#initialization', function() {
|
||||
it('should be initialized with a domain', function() {
|
||||
var client = new VaultClient({ domain: exampleData.domain });
|
||||
assert.strictEqual(client.domain, exampleData.domain);
|
||||
});
|
||||
|
||||
it('should default to ripple.com without a domain', function () {
|
||||
var client = new VaultClient();
|
||||
assert.strictEqual(client.domain, 'ripple.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#exists', function() {
|
||||
it('should determine if a username exists on the domain', function(done) {
|
||||
this.timeout(10000);
|
||||
client.exists(exampleData.username, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'boolean');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#login', function() {
|
||||
it('with username and password should retrive the blob, crypt key, and id', function(done) {
|
||||
this.timeout(10000);
|
||||
client.login(exampleData.username, exampleData.password, exampleData.device_id, function(err, resp) {
|
||||
if (online) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert(resp.blob instanceof Blob);
|
||||
assert.strictEqual(typeof resp.blob.id, 'string');
|
||||
assert(UInt256.from_json(resp.blob.id).is_valid());
|
||||
assert.strictEqual(typeof resp.blob.key, 'string');
|
||||
assert(UInt256.from_json(resp.blob.key).is_valid());
|
||||
assert.strictEqual(typeof resp.username, 'string');
|
||||
assert.strictEqual(typeof resp.verified, 'boolean');
|
||||
} else {
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual(resp, void(0));
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#relogin', function() {
|
||||
it('should retrieve the decrypted blob with blob vault url, id, and crypt key', function(done) {
|
||||
this.timeout(10000);
|
||||
client.relogin(exampleData.blob.url, exampleData.id, exampleData.crypt, exampleData.device_id, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert(resp.blob instanceof Blob);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#unlock', function() {
|
||||
it('should access the wallet secret using encryption secret, username and password', function (done) {
|
||||
this.timeout(10000);
|
||||
client.unlock(exampleData.username, exampleData.password, exampleData.blob.data.encrypted_secret, function(err, resp) {
|
||||
if (online) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.keys, 'object');
|
||||
assert.strictEqual(typeof resp.keys.unlock, 'string');
|
||||
assert(UInt256.from_json(resp.keys.unlock).is_valid());
|
||||
} else {
|
||||
assert.strictEqual(err.toString(), 'CORRUPT: ccm: tag doesn\'t match');
|
||||
assert.strictEqual(resp, void(0));
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#loginAndUnlock', function () {
|
||||
it('should get the decrypted blob and decrypted secret given name and password', function (done) {
|
||||
this.timeout(10000);
|
||||
client.loginAndUnlock(exampleData.username, exampleData.password, exampleData.device_id, function(err, resp) {
|
||||
if (online) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert(resp.blob instanceof Blob);
|
||||
assert.strictEqual(typeof resp.blob.id, 'string');
|
||||
assert(UInt256.from_json(resp.blob.id).is_valid());
|
||||
assert.strictEqual(typeof resp.blob.key, 'string');
|
||||
assert(UInt256.from_json(resp.blob.key).is_valid());
|
||||
assert.strictEqual(typeof resp.unlock, 'string');
|
||||
assert(UInt256.from_json(resp.unlock).is_valid());
|
||||
assert.strictEqual(typeof resp.secret, 'string');
|
||||
assert.strictEqual(typeof resp.username, 'string');
|
||||
assert.strictEqual(typeof resp.verified, 'boolean');
|
||||
} else {
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual(resp, void(0));
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#register', function () {
|
||||
it('should create a new blob', function (done) {
|
||||
this.timeout(10000);
|
||||
var options = {
|
||||
username : exampleData.username,
|
||||
password : exampleData.password,
|
||||
email : exampleData.blob.data.email,
|
||||
activateLink : exampleData.activateLink
|
||||
}
|
||||
|
||||
client.register(options, function(err, resp) {
|
||||
|
||||
//fails, user already exists
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual(resp, void(0));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('#deleteBlob', function () {
|
||||
it('should remove an existing blob', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
var options = {
|
||||
url : exampleData.blob.url,
|
||||
blob_id : exampleData.blob.id,
|
||||
username : online ? "" : exampleData.username,
|
||||
account_id : exampleData.blob.data.account_id,
|
||||
masterkey : exampleData.masterkey
|
||||
}
|
||||
|
||||
client.deleteBlob(options, function(err, resp) {
|
||||
if (online) {
|
||||
//removing the username will result in an error from the server
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual(resp, void(0));
|
||||
} else {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
describe('#updateProfile', function () {
|
||||
it('should update profile parameters associated with a blob', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
var options = {
|
||||
url : exampleData.blob.url,
|
||||
blob_id : exampleData.blob.id,
|
||||
username : exampleData.username,
|
||||
auth_secret : exampleData.blob.data.auth_secret,
|
||||
profile : {
|
||||
city : "San Francisco",
|
||||
phone : "555-555-5555"
|
||||
}
|
||||
}
|
||||
|
||||
client.updateProfile(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('Blob', function () {
|
||||
var client;
|
||||
var resp;
|
||||
|
||||
client = new VaultClient({ domain: exampleData.domain });
|
||||
|
||||
before(function(done) {
|
||||
if (online) {
|
||||
this.timeout(10000);
|
||||
|
||||
client.login(exampleData.username, exampleData.password, exampleData.device_id, function(err, res) {
|
||||
resp = res;
|
||||
blob = res.blob;
|
||||
done();
|
||||
});
|
||||
} else {
|
||||
|
||||
mockBlob.filteringPath(/(blob\/.+)/g, 'blob/')
|
||||
.persist()
|
||||
.post('/v1/blob/')
|
||||
.reply(200, {result:'success'}, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
describe('#rename', function () {
|
||||
it('should change the username of a blob', function (done) {
|
||||
this.timeout(20000);
|
||||
|
||||
var options = {
|
||||
username : exampleData.username,
|
||||
new_username : exampleData.new_username,
|
||||
password : exampleData.password,
|
||||
masterkey : exampleData.masterkey,
|
||||
blob : blob
|
||||
}
|
||||
|
||||
|
||||
client.rename(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
assert.strictEqual(typeof resp.message, 'string');
|
||||
|
||||
if (online) {
|
||||
options.username = exampleData.new_username;
|
||||
options.new_username = exampleData.username;
|
||||
|
||||
//change it back
|
||||
client.rename(options, function(err,resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
assert.strictEqual(typeof resp.message, 'string');
|
||||
done();
|
||||
});
|
||||
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#changePassword', function () {
|
||||
it('should change the password and keys of a blob', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
var options = {
|
||||
username : exampleData.username,
|
||||
password : exampleData.password,
|
||||
masterkey : exampleData.masterkey,
|
||||
blob : blob
|
||||
}
|
||||
|
||||
client.changePassword(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
assert.strictEqual(typeof resp.message, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#recoverBlob', function () {
|
||||
it('should recover the blob given a username and secret', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
var options = {
|
||||
url : exampleData.blob.url,
|
||||
username : exampleData.username,
|
||||
masterkey : exampleData.masterkey,
|
||||
}
|
||||
|
||||
client.recoverBlob(options, function(err, blob) {
|
||||
assert.ifError(err);
|
||||
assert(blob instanceof Blob);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#verifyEmail', function () {
|
||||
it('should verify an email given a username and token', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
client.verify(exampleData.username, exampleData.email_token, function(err, resp) {
|
||||
//result will be error, because of invalid token
|
||||
assert(err instanceof Error);
|
||||
assert.strictEqual(resp, void(0));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#resendVerifcationEmail', function () {
|
||||
it('should resend a verification given options', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
var options = {
|
||||
url : exampleData.blob.url,
|
||||
id : exampleData.blob.id,
|
||||
username : exampleData.username,
|
||||
account_id : exampleData.blob.data.account_id,
|
||||
email : exampleData.blob.data.email,
|
||||
activateLink : exampleData.activateLink,
|
||||
masterkey : exampleData.masterkey
|
||||
}
|
||||
client.resendEmail(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('#set', function(done) {
|
||||
this.timeout(10000)
|
||||
blob.extend('/testObject', {
|
||||
foo: [],
|
||||
}, function(err, resp) {
|
||||
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#extend', function(done) {
|
||||
this.timeout(10000)
|
||||
blob.extend('/testObject', {
|
||||
foobar: 'baz',
|
||||
}, function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#unset', function(done) {
|
||||
this.timeout(10000)
|
||||
blob.unset('/testObject', function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#unshift', function(done) {
|
||||
this.timeout(10000)
|
||||
blob.unshift('/testArray', {
|
||||
name: 'bob',
|
||||
address: '1234'
|
||||
}, function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#filter', function(done) {
|
||||
this.timeout(10000)
|
||||
|
||||
blob.filter('/testArray', 'name', 'bob', 'extend', '', {description:'Alice'}, function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#consolidate', function(done) {
|
||||
this.timeout(10000)
|
||||
blob.unset('/testArray', function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
blob.consolidate(function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('identity', function() {
|
||||
it('#identity_set', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
blob.identity.set('address', exampleData.unlock, {city:"San Francisco", region:"CA"}, function (err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#identity_get', function () {
|
||||
var property = blob.identity.get('address', exampleData.unlock);
|
||||
assert.ifError(property.error);
|
||||
assert.strictEqual(typeof property.encrypted, 'boolean');
|
||||
assert.notEqual(typeof property.value, 'undefined');
|
||||
});
|
||||
|
||||
it('#identity_getAll', function () {
|
||||
var obj = blob.identity.getAll(exampleData.unlock);
|
||||
assert.strictEqual(typeof obj, 'object');
|
||||
});
|
||||
|
||||
it('#identity_getFullAddress', function () {
|
||||
var address = blob.identity.getFullAddress(exampleData.unlock);
|
||||
assert.strictEqual(typeof address, 'string');
|
||||
});
|
||||
|
||||
it('#identity_unset', function (done) {
|
||||
this.timeout(10000);
|
||||
|
||||
blob.identity.unset('name', exampleData.unlock, function (err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('identityVault', function() {
|
||||
it('#identity - Get Attestation', function (done) {
|
||||
var options = {
|
||||
url : blob.url,
|
||||
auth_secret : blob.data.auth_secret,
|
||||
blob_id : blob.id,
|
||||
};
|
||||
|
||||
options.type = 'identity';
|
||||
|
||||
nock('https://id.staging.ripple.com')
|
||||
.filteringPath(/(v1\/attestation\/identity(.+))/g, '')
|
||||
.post('/')
|
||||
.reply(200, {
|
||||
result: 'success',
|
||||
status: 'verified',
|
||||
attestation: 'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig',
|
||||
blinded:'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig'
|
||||
}, {'Content-Type': 'application/json'});
|
||||
|
||||
client.getAttestation(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
assert.strictEqual(typeof resp.attestation, 'string');
|
||||
assert.strictEqual(typeof resp.blinded, 'string');
|
||||
assert.deepEqual(resp.decoded, {"header":{"z":"z"},"payload":{"z":"z"},"signature":"sig"})
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#identity - Update Attestation', function (done) {
|
||||
|
||||
var options = {
|
||||
url : blob.url,
|
||||
auth_secret : blob.data.auth_secret,
|
||||
blob_id : blob.id,
|
||||
};
|
||||
|
||||
options.type = 'identity';
|
||||
|
||||
nock('https://id.staging.ripple.com')
|
||||
.filteringPath(/(v1\/attestation\/identity\/update(.+))/g, '')
|
||||
.post('/')
|
||||
.reply(200, {
|
||||
result: 'success',
|
||||
status: 'verified',
|
||||
attestation: 'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig',
|
||||
blinded:'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig'
|
||||
}, {'Content-Type': 'application/json'});
|
||||
|
||||
client.updateAttestation(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
assert.strictEqual(typeof resp.attestation, 'string');
|
||||
assert.strictEqual(typeof resp.blinded, 'string');
|
||||
assert.deepEqual(resp.decoded, {"header":{"z":"z"},"payload":{"z":"z"},"signature":"sig"})
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#identity - Get Attestation Summary', function (done) {
|
||||
|
||||
var options = {
|
||||
url : blob.url,
|
||||
auth_secret : blob.data.auth_secret,
|
||||
blob_id : blob.id,
|
||||
};
|
||||
|
||||
nock('https://id.staging.ripple.com')
|
||||
.filteringPath(/(v1\/attestation\/summary(.+))/g, '')
|
||||
.get('/')
|
||||
.reply(200, {
|
||||
result: 'success',
|
||||
attestation: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjY2ZGI3MzgxIn0%3D.eyJwcm9maWxlX3ZlcmlmaWVkIjpmYWxzZSwiaWRlbnRpdHlfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwczovL2lkLnJpcHBsZS5jb20iLCJzdWIiOiIwNDMzNTA0ZS0yYTRmLTQ1NjktODQwMi1lYWI2YTU0YTgzYjUiLCJleHAiOjE0MTI4MTc2NjksImlhdCI6MTQxMjgxNTgwOX0%3D.Jt14Y2TsM7fKqGWn0j16cPldlYqRr7%2F2dptBsdZuZhRGRTREO4TSpZZhBaU95WL3M9eXIfaoSs8f2pTOa%2BBGAYHZSZK4%2FLqeWdDH8zz8Bx9YFqGije1KmHQR%2FeoWSp1GTEfcq5Oho4nSHozHhGNN8IrDkl8woMvWb%2FE1938Y5Zl2vyv7wjlNUF4ND33XWzJkvQjzIK15uYfaB%2FUIsNW32udfHAdkigesdMDNm%2BRGBqHMDZeAMdVxzrDzE3m8oWKDMJXbcaLmk75COfJrLWYiZCHd7VcReyPEZegwEucetZJ9uDnoBcvw0%2B6hIRmjTN6Gy1eeBoJaiDYsWuOwInbIlw%3D%3D',
|
||||
}, {'Content-Type': 'application/json'});
|
||||
|
||||
client.getAttestationSummary(options, function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(resp.result, 'success');
|
||||
assert.strictEqual(typeof resp.attestation, 'string');
|
||||
assert.strictEqual(typeof resp.decoded.header, 'object');
|
||||
assert.strictEqual(typeof resp.decoded.payload, 'object');
|
||||
assert.strictEqual(typeof resp.decoded.signature, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
//only do these offline
|
||||
if (!online) {
|
||||
|
||||
describe('2FA', function() {
|
||||
|
||||
it('#2FA_set2FA', function (done) {
|
||||
blob.set2FA({masterkey:exampleData.masterkey}, function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#2FA_get2FA', function (done) {
|
||||
blob.get2FA(function(err, resp) {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#2FA_requestToken', function (done) {
|
||||
client.requestToken(exampleData.blob.url, exampleData.blob.id, function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('#2FA_verifyToken', function (done) {
|
||||
var options = {
|
||||
url : exampleData.blob.url,
|
||||
id : exampleData.blob.id,
|
||||
device_id : client.generateDeviceID(),
|
||||
token : "5555",
|
||||
remember_me : true
|
||||
}
|
||||
|
||||
client.verifyToken(options, function(err, resp){
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(typeof resp, 'object');
|
||||
assert.strictEqual(typeof resp.result, 'string');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!online) {
|
||||
after(function () {
|
||||
nock.restore();
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user