mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-15 18:15:49 +00:00
Compare commits
230 Commits
0.10.0
...
0.12.3-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c40d643238 | ||
|
|
6f23c88567 | ||
|
|
56958a6242 | ||
|
|
74dac97b36 | ||
|
|
2f2e41c781 | ||
|
|
8c872f71c6 | ||
|
|
b40b496866 | ||
|
|
569fec296e | ||
|
|
56d8aa797a | ||
|
|
fe7e30b737 | ||
|
|
a114281c60 | ||
|
|
d09548d04d | ||
|
|
a02b8e3e5c | ||
|
|
2c3f9ca202 | ||
|
|
587782820d | ||
|
|
8fad048569 | ||
|
|
f7c35b118e | ||
|
|
65a669bbb2 | ||
|
|
9985acc539 | ||
|
|
f1f0a43f21 | ||
|
|
6b856c3cc5 | ||
|
|
d92888ed73 | ||
|
|
0357840654 | ||
|
|
53cae3a66d | ||
|
|
949a1ca4ae | ||
|
|
e667536a5b | ||
|
|
dde000a4bb | ||
|
|
aa1f5a8e7d | ||
|
|
bfbfcc2894 | ||
|
|
6abfa759aa | ||
|
|
7cbac2e757 | ||
|
|
1012381d3d | ||
|
|
6de96f62df | ||
|
|
e2ed2bdbf6 | ||
|
|
e248c54aa5 | ||
|
|
1c9635edad | ||
|
|
25cf6c52e4 | ||
|
|
7859ef6145 | ||
|
|
6efaa4ac7e | ||
|
|
19e17a8431 | ||
|
|
c865ae9734 | ||
|
|
6959f74073 | ||
|
|
9f4d21e976 | ||
|
|
719f39c01c | ||
|
|
25bb9c7320 | ||
|
|
a160e16abd | ||
|
|
ec31841aa5 | ||
|
|
3e249902c4 | ||
|
|
21bb766f06 | ||
|
|
a883151400 | ||
|
|
3c7fe82cbd | ||
|
|
899fc09704 | ||
|
|
daa45a44b9 | ||
|
|
52494628c3 | ||
|
|
dbf5d21b72 | ||
|
|
441bd4dfbf | ||
|
|
8452f05dda | ||
|
|
0d2325e646 | ||
|
|
90329d3d73 | ||
|
|
ca83a142f8 | ||
|
|
d3b2d3d5c5 | ||
|
|
255177487c | ||
|
|
ed0b75bcde | ||
|
|
06500a7909 | ||
|
|
6e16bf68ae | ||
|
|
ad22480117 | ||
|
|
2fcd09072f | ||
|
|
f0c785b196 | ||
|
|
84fe76bada | ||
|
|
b5ed8f59a7 | ||
|
|
52526f90d7 | ||
|
|
99e6e81e65 | ||
|
|
5af824f5cf | ||
|
|
2166bb2e88 | ||
|
|
ae884c0200 | ||
|
|
423ec7d08a | ||
|
|
914cd6ecb2 | ||
|
|
f221c82859 | ||
|
|
d57be723e6 | ||
|
|
777554809a | ||
|
|
f2b63fa4a8 | ||
|
|
4d06ce7454 | ||
|
|
8da6ec5fa3 | ||
|
|
2a5a8b498d | ||
|
|
a9b7d7d793 | ||
|
|
6578cf5dd7 | ||
|
|
2e21e8a43c | ||
|
|
176e1fd9d4 | ||
|
|
c3b274b18f | ||
|
|
8e134918fb | ||
|
|
2b531d2a1f | ||
|
|
87317dd54a | ||
|
|
618548c88d | ||
|
|
b62f42006c | ||
|
|
c275174f27 | ||
|
|
af4ed295e0 | ||
|
|
7614a03ea8 | ||
|
|
d9527726b6 | ||
|
|
05f4099709 | ||
|
|
a20a649013 | ||
|
|
0e3e64105c | ||
|
|
b2cdb1a6ae | ||
|
|
812432db96 | ||
|
|
5b2c4aef2d | ||
|
|
b7ccf424f4 | ||
|
|
77d5db168b | ||
|
|
e80cd1ff55 | ||
|
|
4ff25a21f6 | ||
|
|
f184a71360 | ||
|
|
fc38a9853d | ||
|
|
6023efed41 | ||
|
|
2abac6ce5c | ||
|
|
53c7705c36 | ||
|
|
7059ab65d6 | ||
|
|
e133988b36 | ||
|
|
9af27e7964 | ||
|
|
a57b3835fb | ||
|
|
451cbb809e | ||
|
|
fd1b64393d | ||
|
|
ed875a35b4 | ||
|
|
e85b0c2122 | ||
|
|
f5b192f55f | ||
|
|
ff86d5381d | ||
|
|
b63ac4addb | ||
|
|
3e1a66d617 | ||
|
|
93ed5a8cae | ||
|
|
2e6e8807be | ||
|
|
1ed36fabdb | ||
|
|
8dc40ee379 | ||
|
|
db4c7c89e3 | ||
|
|
f9bc7cc746 | ||
|
|
8f87ed65f9 | ||
|
|
39c37631f3 | ||
|
|
d0fb291c4e | ||
|
|
793523cbe9 | ||
|
|
6da4dd9ecc | ||
|
|
79892af8f8 | ||
|
|
b86790c854 | ||
|
|
c8f18c8c85 | ||
|
|
b19ecb4482 | ||
|
|
ba9af55aca | ||
|
|
35d76b3520 | ||
|
|
a5a0326092 | ||
|
|
a05833f845 | ||
|
|
c5deb60510 | ||
|
|
ff2ff89e3e | ||
|
|
35a346a674 | ||
|
|
1217a95c52 | ||
|
|
d025b4a0c3 | ||
|
|
2cab50f920 | ||
|
|
b049278dde | ||
|
|
93335e74cb | ||
|
|
2833a7b66e | ||
|
|
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 | ||
|
|
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 |
7
.flowconfig
Normal file
7
.flowconfig
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[ignore]
|
||||||
|
|
||||||
|
[include]
|
||||||
|
|
||||||
|
[libs]
|
||||||
|
|
||||||
|
[options]
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -25,6 +25,7 @@ Release/*.*
|
|||||||
|
|
||||||
# Ignore locally installed node_modules
|
# Ignore locally installed node_modules
|
||||||
node_modules
|
node_modules
|
||||||
|
!test/node_modules
|
||||||
|
|
||||||
# Ignore tmp directory.
|
# Ignore tmp directory.
|
||||||
tmp
|
tmp
|
||||||
@@ -52,3 +53,11 @@ npm-debug.log
|
|||||||
|
|
||||||
# Ignore dist folder, build for bower
|
# Ignore dist folder, build for bower
|
||||||
dist/
|
dist/
|
||||||
|
|
||||||
|
# Ignore flow output directory
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Ignore perf test cache
|
||||||
|
scripts/cache
|
||||||
|
|
||||||
|
eslintrc
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "0.10"
|
- "0.10"
|
||||||
script: npm test --coverage
|
before_script:
|
||||||
|
- npm install -g eslint
|
||||||
|
- curl 'https://raw.githubusercontent.com/ripple/javascript-style-guide/master/eslintrc' > ./eslintrc
|
||||||
|
- eslint --reset -c ./eslintrc $(git --no-pager diff --name-only --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD | grep "\.js$")
|
||||||
|
script: MOCHA_REPORTER=tap npm test --coverage
|
||||||
after_success:
|
after_success:
|
||||||
- npm run coveralls
|
- npm run coveralls
|
||||||
notifications:
|
notifications:
|
||||||
|
email: false
|
||||||
webhooks:
|
webhooks:
|
||||||
urls:
|
urls:
|
||||||
- https://webhooks.gitter.im/e/d1ec4245f90231619d30
|
- https://webhooks.gitter.im/e/d1ec4245f90231619d30
|
||||||
|
|||||||
85
Gulpfile.js
85
Gulpfile.js
@@ -1,22 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
var gulp = require('gulp');
|
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 concat = require('gulp-concat');
|
||||||
var uglify = require('gulp-uglify');
|
var uglify = require('gulp-uglify');
|
||||||
var rename = require('gulp-rename');
|
var rename = require('gulp-rename');
|
||||||
var webpack = require('webpack');
|
var webpack = require('webpack');
|
||||||
var jshint = require('gulp-jshint');
|
|
||||||
var map = require('map-stream');
|
|
||||||
var bump = require('gulp-bump');
|
var bump = require('gulp-bump');
|
||||||
|
var react = require('gulp-react');
|
||||||
|
var flow = require('gulp-flowtype');
|
||||||
var argv = require('yargs').argv;
|
var argv = require('yargs').argv;
|
||||||
// var header = require('gulp-header');
|
// var header = require('gulp-header');
|
||||||
|
|
||||||
var pkg = require('./package.json');
|
var pkg = require('./package.json');
|
||||||
|
|
||||||
var banner = '/*! <%= pkg.name %> - v<%= pkg.version %> - '
|
|
||||||
+ '<%= new Date().toISOString() %>\n'
|
|
||||||
+ '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>'
|
|
||||||
+ '* Copyright (c) <%= new Date().getFullYear() %> <%= pkg.author.name %>;'
|
|
||||||
+ ' Licensed <%= pkg.license %> */'
|
|
||||||
|
|
||||||
var sjclSrc = [
|
var sjclSrc = [
|
||||||
'src/js/sjcl/core/sjcl.js',
|
'src/js/sjcl/core/sjcl.js',
|
||||||
'src/js/sjcl/core/aes.js',
|
'src/js/sjcl/core/aes.js',
|
||||||
@@ -50,6 +50,10 @@ var sjclSrc = [
|
|||||||
'src/js/sjcl-custom/sjcl-jacobi.js'
|
'src/js/sjcl-custom/sjcl-jacobi.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function logPluginError(error) {
|
||||||
|
gutil.log(error.toString());
|
||||||
|
}
|
||||||
|
|
||||||
gulp.task('concat-sjcl', function() {
|
gulp.task('concat-sjcl', function() {
|
||||||
return gulp.src(sjclSrc)
|
return gulp.src(sjclSrc)
|
||||||
.pipe(concat('sjcl.js'))
|
.pipe(concat('sjcl.js'))
|
||||||
@@ -64,11 +68,11 @@ gulp.task('build', [ 'concat-sjcl' ], function(callback) {
|
|||||||
library: 'ripple',
|
library: 'ripple',
|
||||||
path: './build/',
|
path: './build/',
|
||||||
filename: ['ripple-', '.js'].join(pkg.version)
|
filename: ['ripple-', '.js'].join(pkg.version)
|
||||||
},
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build-min', [ 'build' ], function(callback) {
|
gulp.task('build-min', ['build'], function() {
|
||||||
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
||||||
.pipe(uglify())
|
.pipe(uglify())
|
||||||
.pipe(rename(['ripple-', '-min.js'].join(pkg.version)))
|
.pipe(rename(['ripple-', '-min.js'].join(pkg.version)))
|
||||||
@@ -95,9 +99,10 @@ gulp.task('build-debug', [ 'concat-sjcl' ], function(callback) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function buildUseError(cons) {
|
function buildUseError(cons) {
|
||||||
return 'var {<CONS>:function(){throw new Error("Class is unavailable in this build: <CONS>")}}'
|
return ('var {<CONS>:function(){throw new Error('
|
||||||
|
+ '"Class is unavailable in this build: <CONS>")}}')
|
||||||
.replace(new RegExp('<CONS>', 'g'), cons);
|
.replace(new RegExp('<CONS>', 'g'), cons);
|
||||||
};
|
}
|
||||||
|
|
||||||
gulp.task('build-core', ['concat-sjcl'], function(callback) {
|
gulp.task('build-core', ['concat-sjcl'], function(callback) {
|
||||||
webpack({
|
webpack({
|
||||||
@@ -123,19 +128,19 @@ gulp.task('build-core', [ 'concat-sjcl' ], function(callback) {
|
|||||||
}, callback);
|
}, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('bower-build', [ 'build' ], function(callback) {
|
gulp.task('bower-build', ['build'], function() {
|
||||||
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
|
||||||
.pipe(rename('ripple.js'))
|
.pipe(rename('ripple.js'))
|
||||||
.pipe(gulp.dest('./dist/'));
|
.pipe(gulp.dest('./dist/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('bower-build-min', [ 'build-min' ], function(callback) {
|
gulp.task('bower-build-min', ['build-min'], function() {
|
||||||
return gulp.src(['./build/ripple-', '-min.js'].join(pkg.version))
|
return gulp.src(['./build/ripple-', '-min.js'].join(pkg.version))
|
||||||
.pipe(rename('ripple-min.js'))
|
.pipe(rename('ripple-min.js'))
|
||||||
.pipe(gulp.dest('./dist/'));
|
.pipe(gulp.dest('./dist/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('bower-build-debug', [ 'build-debug' ], function(callback) {
|
gulp.task('bower-build-debug', ['build-debug'], function() {
|
||||||
return gulp.src(['./build/ripple-', '-debug.js'].join(pkg.version))
|
return gulp.src(['./build/ripple-', '-debug.js'].join(pkg.version))
|
||||||
.pipe(rename('ripple-debug.js'))
|
.pipe(rename('ripple-debug.js'))
|
||||||
.pipe(gulp.dest('./dist/'));
|
.pipe(gulp.dest('./dist/'));
|
||||||
@@ -147,41 +152,35 @@ gulp.task('bower-version', function() {
|
|||||||
.pipe(gulp.dest('./dist/'));
|
.pipe(gulp.dest('./dist/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug', 'bower-version']);
|
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);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task('watch', function() {
|
gulp.task('watch', function() {
|
||||||
gulp.watch('src/js/ripple/*', ['build-debug']);
|
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() {
|
gulp.task('version-bump', function() {
|
||||||
if (!argv.type) {
|
if (!argv.type) {
|
||||||
throw new Error("No type found, pass it in using the --type argument");
|
throw new Error('No type found, pass it in using the --type argument');
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.src('./package.json')
|
gulp.src('./package.json')
|
||||||
|
|||||||
117
HISTORY.md
117
HISTORY.md
@@ -1,3 +1,120 @@
|
|||||||
|
##0.12.3
|
||||||
|
|
||||||
|
+ [Add getLedgerSequence to Remote](https://github.com/ripple/ripple-lib/commit/d09548d04d3238fca653d482ec1d5faa7254559a)
|
||||||
|
|
||||||
|
+ [Improve randomness when generating ECDSA signatures](https://github.com/ripple/ripple-lib/commit/fe7e30b737ead6e71adfa466f5835ba546feab31)
|
||||||
|
|
||||||
|
+ [Improve SerializedObject.append performance](https://github.com/ripple/ripple-lib/commit/f7c35b118ebba549a64bcaa1a0629385ec6dbf6f)
|
||||||
|
|
||||||
|
+ [Add `Amount.scale`. Multiply an amount’s value by a scale factor](https://github.com/ripple/ripple-lib/commit/74dac97b368493056474468520f05671f458a69f)
|
||||||
|
|
||||||
|
|
||||||
|
##0.12.2
|
||||||
|
|
||||||
|
+ [Check that stack trace is available, fixes logging in browser](https://github.com/ripple/ripple-lib/commit/53cae3a66d48e88e8a6bbb96d6489ce7b9e22975)
|
||||||
|
|
||||||
|
|
||||||
|
##0.12.1
|
||||||
|
|
||||||
|
**Breaking Changes**
|
||||||
|
|
||||||
|
+ [Removed support for parsing native amounts in floating point format](https://github.com/ripple/ripple-lib/commit/e80cd1ff55deae9cd5b0ae85be957f86856b887e)
|
||||||
|
|
||||||
|
|
||||||
|
**Changes**
|
||||||
|
|
||||||
|
+ [Fix taker pays funded calculation](https://github.com/ripple/ripple-lib/commit/5af824f5cf46c7b9caa58ee0a757bf854d26c8dc)
|
||||||
|
|
||||||
|
+ [Fix order funded amount calculation](https://github.com/ripple/ripple-lib/commit/b2cdb1a6aed968b1f306e8dadbd4b7ca37e5aa03)
|
||||||
|
|
||||||
|
+ [Fix handling of quality in order book](https://github.com/ripple/ripple-lib/commit/2a5a8b498da60df738ba18d5c265f34771e8a1af)
|
||||||
|
|
||||||
|
+ [Fix currency parsing of non-alphanumeric and no-currency currencies](https://github.com/ripple/ripple-lib/commit/2166bb2e88eae8d5f1aba77338f69e8a9edf6a6f)
|
||||||
|
|
||||||
|
+ [Add Amount.strict_mode for toggling range validation](https://github.com/ripple/ripple-lib/commit/b5ed8f59a7dab1a17491618b8d9193646c314fb4)
|
||||||
|
|
||||||
|
+ [Add filename and line number to log, use log.warn() for deprecations](https://github.com/ripple/ripple-lib/commit/90329d3d73f1a76675063655b407513e32dc048b)
|
||||||
|
|
||||||
|
+ [Add GlobalFreeze and NoFreeze flags](https://github.com/ripple/ripple-lib/commit/e2ed2bdbf6f01c7d4d690c2cf0b83fba94558dd7)
|
||||||
|
|
||||||
|
+ [Fix handling of falsy parameters in requestLedger](https://github.com/ripple/ripple-lib/commit/6023efed41b7812b3bab660a1c0dc9f0a21000b9)
|
||||||
|
|
||||||
|
+ [Fix Base:decode](https://github.com/ripple/ripple-lib/commit/719f39c01c6941d9a650aa94f95617793dd53ea0)
|
||||||
|
|
||||||
|
+ [Fix Amount: clone in ratio_human, product_human](https://github.com/ripple/ripple-lib/commit/19e17a8431550cf156b1ad669a19dedfe4e28e4a)
|
||||||
|
|
||||||
|
+ [Fix Amount.to_human for very small numbers](https://github.com/ripple/ripple-lib/commit/6abfa759aa09d68074ac558d96c4b126a7cd1719)
|
||||||
|
|
||||||
|
+ [Refactor base conversion](https://github.com/ripple/ripple-lib/commit/f2b63fa4a80663eb29472bc6bb1aea8159f1f205)
|
||||||
|
|
||||||
|
+ [Update binary transaction format](https://github.com/ripple/ripple-lib/commit/8e134918fb4c22983320a3102f955e4568bb1dfb)
|
||||||
|
|
||||||
|
+ [Add DefaultRipple account flag](https://github.com/ripple/ripple-lib/commit/3e249902c4cf25b4da5e75048c84ae391be83b10)
|
||||||
|
|
||||||
|
+ [Remove `Features` field requirement in `SetFee` transaction format](https://github.com/ripple/ripple-lib/commit/a20a649013646710c078d4ce1e210f87c7fe74fe)
|
||||||
|
|
||||||
|
+ [Remove `RegularKey` field requirement in `SetRegularKey` transaction format](https://github.com/ripple/ripple-lib/commit/c275174f27877ba8f389eb4efe969feb514d6e46)
|
||||||
|
|
||||||
|
|
||||||
|
##0.12.0
|
||||||
|
|
||||||
|
**Breaking Changes**
|
||||||
|
|
||||||
|
+ REMOVED Remote storage interface
|
||||||
|
+ REMOVED Remote `ping` configuration
|
||||||
|
+ REMOVED Old/deprecated Remote server configuration (websocket_ip, websocket_port)
|
||||||
|
+ REMOVED browser `online` reconnect listener
|
||||||
|
- [Cleanup, deprecations - 2833a7b6](https://github.com/ripple/ripple-lib/commit/2833a7b66e696dab427464625077f9b93092d0d5)
|
||||||
|
|
||||||
|
+ Remove `jsbn` and use `bignumber.js` instead for big number math
|
||||||
|
+ The `allow_nan` flag has been removed. Results for invalid amounts will always be `NaN`
|
||||||
|
- [Refactor to use bignumber.js - d025b4a0](https://github.com/ripple/ripple-lib/commit/d025b4a0c3a98a6de27a1bee9573c85347bcd66b)
|
||||||
|
- [Handle invalid input in parse_human - c8f18c8c](https://github.com/ripple/ripple-lib/commit/c8f18c8c8590b7b48e370e0325b6677b7720294f)
|
||||||
|
- [Check for null in isNumber - b86790c8](https://github.com/ripple/ripple-lib/commit/b86790c8543c239a532fd7697d4652829019d385)
|
||||||
|
- [Cleanup amount.js - d0fb291c](https://github.com/ripple/ripple-lib/commit/d0fb291c4e330193a244902156f1d74730da357d)
|
||||||
|
|
||||||
|
|
||||||
|
**Changes**
|
||||||
|
|
||||||
|
+ [Add deprecation warnings to request constructors. The first argument to request constructor functions should be an object containing request properties](https://github.com/ripple/ripple-lib/commit/35d76b3520934285f80059c1badd6c522539104c)
|
||||||
|
|
||||||
|
+ [Fix taker_gets_funded exceeding offer.TakerGets](https://github.com/ripple/ripple-lib/commit/b19ecb4482b589d575382b7a5d0480b963383bb1)
|
||||||
|
|
||||||
|
+ [Fix unsymmetric memo serializing](https://github.com/ripple/ripple-lib/commit/1ed36fabdbd54f4d31078c2b0eaa3becc0fe2821)
|
||||||
|
|
||||||
|
+ [Fix IOU value passed to `Amount.from_json()`](https://github.com/ripple/ripple-lib/commit/fd1b64393dffb3d1819cd40b8d43df43a4db042d)
|
||||||
|
|
||||||
|
+ [Update transaction binary parsing to account for XRP delivered amounts](https://github.com/ripple/ripple-lib/commit/35a346a674e6ee1e1e495db93700d55984efc7dd)
|
||||||
|
|
||||||
|
+ [Bumped dependencies](https://github.com/ripple/ripple-lib/commit/f9bc7cc746b44b24b61bbe260ae2e9d9617286da)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
##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
|
##0.10.0
|
||||||
|
|
||||||
+ [Transaction changes](https://github.com/ripple/ripple-lib/pull/221)
|
+ [Transaction changes](https://github.com/ripple/ripple-lib/pull/221)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ A JavaScript API for interacting with Ripple in Node.js and the browser
|
|||||||
###Features
|
###Features
|
||||||
|
|
||||||
+ Connect to a rippled server in JavaScript (Node.js or browser)
|
+ 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.)
|
+ Listen to events on the Ripple network (transaction, ledger, etc.)
|
||||||
+ Sign and submit transactions to the Ripple network
|
+ 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
|
||||||
@@ -18,7 +18,7 @@ This file provides step-by-step walkthroughs for some of the most common usages
|
|||||||
|
|
||||||
##Connecting to the Ripple network
|
##Connecting to the Ripple network
|
||||||
|
|
||||||
1. [Get ripple-lib](README.md#getting-ripple-lib)
|
1. [Get ripple-lib](../README.md#installation)
|
||||||
2. Load the ripple-lib module into a Node.js file or webpage:
|
2. Load the ripple-lib module into a Node.js file or webpage:
|
||||||
```js
|
```js
|
||||||
/* Loading ripple-lib with Node.js */
|
/* Loading ripple-lib with Node.js */
|
||||||
@@ -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.connect(function(err, res) {
|
||||||
/* remote connected, use some remote functions here */
|
/* remote connected, use some remote functions here */
|
||||||
|
|||||||
88
npm-shrinkwrap.json
generated
88
npm-shrinkwrap.json
generated
@@ -1,26 +1,36 @@
|
|||||||
{
|
{
|
||||||
"name": "ripple-lib",
|
"name": "ripple-lib",
|
||||||
"version": "0.10.0",
|
"version": "0.12.3-rc2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": {
|
"async": {
|
||||||
"version": "0.8.0",
|
"version": "0.9.0",
|
||||||
"from": "async@>=0.8.0 <0.9.0",
|
"from": "async@>=0.9.0 <0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-0.8.0.tgz"
|
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
|
||||||
|
},
|
||||||
|
"bignumber.js": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"from": "bignumber.js@>=2.0.3 <3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.0.3.tgz"
|
||||||
},
|
},
|
||||||
"extend": {
|
"extend": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"from": "extend@>=1.2.1 <1.3.0",
|
"from": "extend@>=1.2.1 <1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
|
||||||
},
|
},
|
||||||
|
"lodash": {
|
||||||
|
"version": "3.5.0",
|
||||||
|
"from": "lodash@>=3.1.0 <4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz"
|
||||||
|
},
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"from": "lru-cache@>=2.5.0 <2.6.0",
|
"from": "lru-cache@>=2.5.0 <2.6.0",
|
||||||
"resolved": "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": {
|
"ripple-wallet-generator": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"from": "ripple-wallet-generator@1.0.1",
|
"from": "ripple-wallet-generator@1.0.2",
|
||||||
"resolved": "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.2.tgz"
|
||||||
},
|
},
|
||||||
"superagent": {
|
"superagent": {
|
||||||
"version": "0.18.2",
|
"version": "0.18.2",
|
||||||
@@ -90,11 +100,6 @@
|
|||||||
"resolved": "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",
|
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -128,26 +133,51 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"version": "0.4.32",
|
"version": "0.7.1",
|
||||||
"from": "ws@>=0.4.31 <0.5.0",
|
"from": "ws@>=0.7.1 <0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-0.7.1.tgz",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"from": "commander@>=2.1.0 <2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz"
|
|
||||||
},
|
|
||||||
"nan": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"from": "nan@>=1.0.0 <1.1.0"
|
|
||||||
},
|
|
||||||
"tinycolor": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"from": "tinycolor@>=0.0.0 <1.0.0"
|
|
||||||
},
|
|
||||||
"options": {
|
"options": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"from": "options@>=0.0.5"
|
"from": "options@>=0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
|
||||||
|
},
|
||||||
|
"ultron": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"from": "ultron@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.1.tgz"
|
||||||
|
},
|
||||||
|
"bufferutil": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"from": "bufferutil@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.0.1.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"from": "bindings@>=1.2.0 <1.3.0"
|
||||||
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"from": "nan@>=1.6.0 <1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.2.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"from": "utf-8-validate@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.0.1.tgz",
|
||||||
|
"dependencies": {
|
||||||
|
"bindings": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"from": "bindings@>=1.2.0 <1.3.0"
|
||||||
|
},
|
||||||
|
"nan": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"from": "nan@>=1.6.0 <1.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-1.6.2.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
package.json
46
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ripple-lib",
|
"name": "ripple-lib",
|
||||||
"version": "0.10.0",
|
"version": "0.12.3-rc2",
|
||||||
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
|
||||||
"files": [
|
"files": [
|
||||||
"src/js/*",
|
"src/js/*",
|
||||||
@@ -15,33 +15,45 @@
|
|||||||
"test": "test"
|
"test": "test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "~0.8.0",
|
"async": "~0.9.0",
|
||||||
"ws": "~0.4.31",
|
"bignumber.js": "^2.0.3",
|
||||||
"extend": "~1.2.1",
|
"extend": "~1.2.1",
|
||||||
|
"lodash": "^3.1.0",
|
||||||
"lru-cache": "~2.5.0",
|
"lru-cache": "~2.5.0",
|
||||||
"superagent": "^0.18.0",
|
"ripple-wallet-generator": "1.0.2",
|
||||||
"ripple-wallet-generator": "1.0.1"
|
"ws": "~0.7.1",
|
||||||
|
"superagent": "^0.18.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "~1.14.0",
|
"assert-diff": "^1.0.1",
|
||||||
"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",
|
"coveralls": "~2.10.0",
|
||||||
|
"eslint": "^0.18.0",
|
||||||
|
"gulp": "~3.8.10",
|
||||||
|
"gulp-bump": "~0.1.13",
|
||||||
|
"gulp-clean-dest": "^0.1.0",
|
||||||
|
"gulp-concat": "~2.4.3",
|
||||||
|
"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": "~1.1.0",
|
||||||
|
"gulp-util": "^3.0.3",
|
||||||
|
"gulp-watch": "^4.1.0",
|
||||||
|
"istanbul": "~0.3.5",
|
||||||
|
"map-stream": "~0.1.0",
|
||||||
|
"mocha": "~2.1.0",
|
||||||
"nock": "^0.34.1",
|
"nock": "^0.34.1",
|
||||||
|
"webpack": "~1.5.3",
|
||||||
"yargs": "~1.3.1"
|
"yargs": "~1.3.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node_modules/.bin/gulp",
|
"build": "node_modules/.bin/gulp",
|
||||||
"pretest": "node_modules/.bin/gulp concat-sjcl",
|
"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",
|
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter ${MOCHA_REPORTER:=spec} --timeout 10000 --slow 500 test/*-test.js",
|
||||||
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls"
|
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls",
|
||||||
|
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/master/eslintrc'; fi; eslint --reset -c eslintrc src/js/ripple/*.js",
|
||||||
|
"perf": "./scripts/perf_test.sh"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"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"
|
||||||
@@ -1,31 +1,34 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var Amount = require('../src/js/ripple').Amount;
|
||||||
var Ledger = require('../src/js/ripple/ledger').Ledger;
|
var Ledger = require('../src/js/ripple/ledger').Ledger;
|
||||||
|
|
||||||
function parse_options(from, flags) {
|
function parse_options(from, flags) {
|
||||||
var argv = from.slice(),
|
var argv = from.slice(),
|
||||||
opts = {argv:argv};
|
opts_ = {argv: argv};
|
||||||
|
|
||||||
flags.forEach(function(f) {
|
flags.forEach(function(f) {
|
||||||
// Do we have the flag?
|
// Do we have the flag?
|
||||||
var flag_index = argv.indexOf('--' + f);
|
var flag_index = argv.indexOf('--' + f);
|
||||||
// normalize the name of the flag
|
// normalize the name of the flag
|
||||||
f = f.replace('-', '_');
|
f = f.replace('-', '_');
|
||||||
// opts has Boolean value for normalized flag key
|
// opts_ has Boolean value for normalized flag key
|
||||||
opts[f] = !!~flag_index;
|
opts_[f] = flag_index !== -1;
|
||||||
if (opts[f]) {
|
if (opts_[f]) {
|
||||||
// remove the flag from the argv
|
// remove the flag from the argv
|
||||||
argv.splice(flag_index, 1);
|
argv.splice(flag_index, 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return opts;
|
return opts_;
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts = parse_options(process.argv.slice(2), // remove `node` and `this.js`
|
var opts = parse_options(process.argv.slice(2), // remove `node` and `this.js`
|
||||||
['sanity-test']);
|
['sanity-test']);
|
||||||
|
|
||||||
if (opts.argv.length < 1) {
|
if (opts.argv.length < 1) {
|
||||||
console.error("Usage: scripts/verify_ledger_json path/to/ledger.json");
|
console.error('Usage: scripts/verify_ledger_json path/to/ledger.json');
|
||||||
console.error(" optional: --sanity-test (json>binary>json>binary)");
|
console.error(' optional: --sanity-test (json>binary>json>binary)');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,14 +39,27 @@ var ledger = Ledger.from_json(JSON.parse(json));
|
|||||||
// before finally serializing for hashing. This is mostly to expose any issues
|
// before finally serializing for hashing. This is mostly to expose any issues
|
||||||
// with ripple-libs binary <--> json codecs.
|
// with ripple-libs binary <--> json codecs.
|
||||||
if (opts.sanity_test) {
|
if (opts.sanity_test) {
|
||||||
console.log("All accountState nodes will be processed from " +
|
console.log('All accountState nodes will be processed from ' +
|
||||||
"json->binary->json->binary. This may take some time " +
|
'json->binary->json->binary. This may take some time ' +
|
||||||
"with large ledgers.");
|
'with large ledgers.');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Transaction hash in header: " + ledger.ledger_json.transaction_hash);
|
// To recompute the hashes of some ledgers, we must allow values that slipped in
|
||||||
console.log("Calculated transaction hash: " + ledger.calc_tx_hash().to_hex());
|
// before strong policies were in place.
|
||||||
console.log("Account state hash in header: " + ledger.ledger_json.account_hash);
|
Amount.strict_mode = false;
|
||||||
console.log("Calculated account state hash: " + ledger.calc_account_hash(
|
|
||||||
{sanity_test:opts.sanity_test})
|
console.log('Transaction hash in header: ' +
|
||||||
|
ledger.ledger_json.transaction_hash);
|
||||||
|
console.log('Calculated transaction hash: ' +
|
||||||
|
ledger.calc_tx_hash().to_hex());
|
||||||
|
|
||||||
|
console.log('Account state hash in header: ' +
|
||||||
|
ledger.ledger_json.account_hash);
|
||||||
|
|
||||||
|
if (ledger.ledger_json.accountState) {
|
||||||
|
console.log('Calculated account state hash: ' +
|
||||||
|
ledger.calc_account_hash({sanity_test: opts.sanity_test})
|
||||||
.to_hex());
|
.to_hex());
|
||||||
|
} else {
|
||||||
|
console.log('Ledger has no accountState');
|
||||||
|
}
|
||||||
|
|||||||
1210
src/js/jsbn/jsbn.js
1210
src/js/jsbn/jsbn.js
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ function Account(remote, account) {
|
|||||||
if (!self._subs && self._remote._connected) {
|
if (!self._subs && self._remote._connected) {
|
||||||
self._remote.request_subscribe()
|
self._remote.request_subscribe()
|
||||||
.add_account(self._account_id)
|
.add_account(self._account_id)
|
||||||
.broadcast();
|
.broadcast().request();
|
||||||
}
|
}
|
||||||
self._subs += 1;
|
self._subs += 1;
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ function Account(remote, account) {
|
|||||||
if (!self._subs && self._remote._connected) {
|
if (!self._subs && self._remote._connected) {
|
||||||
self._remote.request_unsubscribe()
|
self._remote.request_unsubscribe()
|
||||||
.add_account(self._account_id)
|
.add_account(self._account_id)
|
||||||
.broadcast();
|
.broadcast().request();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
var _ = require('lodash');
|
||||||
var sjcl = require('./utils').sjcl;
|
var sjcl = require('./utils').sjcl;
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
|
var convertBase = require('./baseconverter');
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
|
||||||
|
|
||||||
var Base = {};
|
var Base = {};
|
||||||
|
|
||||||
@@ -24,99 +25,88 @@ extend(Base, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function sha256(bytes) {
|
function sha256(bytes) {
|
||||||
return sjcl.codec.bytes.fromBits(sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
return sjcl.codec.bytes.fromBits(
|
||||||
};
|
sjcl.hash.sha256.hash(sjcl.codec.bytes.toBits(bytes)));
|
||||||
|
}
|
||||||
|
|
||||||
function sha256hash(bytes) {
|
function encodeString(alphabet, input) {
|
||||||
return sha256(sha256(bytes));
|
if (input.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
var leadingZeros = _.takeWhile(input, function(d) {
|
||||||
|
return d === 0;
|
||||||
|
});
|
||||||
|
var out = convertBase(input, 256, 58).map(function(digit) {
|
||||||
|
if (digit < 0 || digit >= alphabet.length) {
|
||||||
|
throw new Error('Value ' + digit + ' is out of bounds for encoding');
|
||||||
|
}
|
||||||
|
return alphabet[digit];
|
||||||
|
});
|
||||||
|
var prefix = leadingZeros.map(function() {
|
||||||
|
return alphabet[0];
|
||||||
|
});
|
||||||
|
return prefix.concat(out).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeString(indexes, input) {
|
||||||
|
if (input.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var input58 = input.split('').map(function(c) {
|
||||||
|
var charCode = c.charCodeAt(0);
|
||||||
|
if (charCode >= indexes.length || indexes[charCode] === -1) {
|
||||||
|
throw new Error('Character ' + c + ' is not valid for encoding');
|
||||||
|
}
|
||||||
|
return indexes[charCode];
|
||||||
|
});
|
||||||
|
var leadingZeros = _.takeWhile(input58, function(d) {
|
||||||
|
return d === 0;
|
||||||
|
});
|
||||||
|
var out = convertBase(input58, 58, 256);
|
||||||
|
return leadingZeros.concat(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Base58(alphabet) {
|
||||||
|
var indexes = utils.arraySet(128, -1);
|
||||||
|
for (var i = 0; i < alphabet.length; i++) {
|
||||||
|
indexes[alphabet.charCodeAt(i)] = i;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
decode: decodeString.bind(null, indexes),
|
||||||
|
encode: encodeString.bind(null, alphabet)
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Base.encoders = {};
|
||||||
|
Object.keys(alphabets).forEach(function(alphabet) {
|
||||||
|
Base.encoders[alphabet] = new Base58(alphabets[alphabet]);
|
||||||
|
});
|
||||||
|
|
||||||
// --> input: big-endian array of bytes.
|
// --> input: big-endian array of bytes.
|
||||||
// <-- string at least as long as input.
|
// <-- string at least as long as input.
|
||||||
Base.encode = function(input, alpha) {
|
Base.encode = function(input, alpha) {
|
||||||
var alphabet = alphabets[alpha || 'ripple'];
|
return this.encoders[alpha || 'ripple'].encode(input);
|
||||||
var bi_base = new BigInteger(String(alphabet.length));
|
|
||||||
var bi_q = new BigInteger();
|
|
||||||
var bi_r = new BigInteger();
|
|
||||||
var bi_value = new BigInteger(input);
|
|
||||||
var buffer = [];
|
|
||||||
|
|
||||||
while (bi_value.compareTo(BigInteger.ZERO) > 0) {
|
|
||||||
bi_value.divRemTo(bi_base, bi_q, bi_r);
|
|
||||||
bi_q.copyTo(bi_value);
|
|
||||||
buffer.push(alphabet[bi_r.intValue()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i=0; i !== input.length && !input[i]; i += 1) {
|
|
||||||
buffer.push(alphabet[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.reverse().join('');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --> input: String
|
// --> input: String
|
||||||
// <-- array of bytes or undefined.
|
// <-- array of bytes or undefined.
|
||||||
Base.decode = function(input, alpha) {
|
Base.decode = function(input, alpha) {
|
||||||
if (typeof input !== 'string') {
|
if (typeof input !== 'string') {
|
||||||
return void(0);
|
return undefined;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
var alphabet = alphabets[alpha || 'ripple'];
|
return this.encoders[alpha || 'ripple'].decode(input);
|
||||||
var bi_base = new BigInteger(String(alphabet.length));
|
} catch (e) {
|
||||||
var bi_value = new BigInteger();
|
return undefined;
|
||||||
var i;
|
|
||||||
|
|
||||||
for (i = 0; i !== input.length && input[i] === alphabet[0]; i += 1) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; i !== input.length; i += 1) {
|
|
||||||
var v = alphabet.indexOf(input[i]);
|
|
||||||
|
|
||||||
if (v < 0) {
|
|
||||||
return void(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var r = new BigInteger();
|
|
||||||
r.fromInt(v);
|
|
||||||
bi_value = bi_value.multiply(bi_base).add(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
// toByteArray:
|
|
||||||
// - Returns leading zeros!
|
|
||||||
// - Returns signed bytes!
|
|
||||||
var bytes = bi_value.toByteArray().map(function(b) { return b ? b < 0 ? 256+b : b : 0; });
|
|
||||||
var extra = 0;
|
|
||||||
|
|
||||||
while (extra !== bytes.length && !bytes[extra]) {
|
|
||||||
extra += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extra) {
|
|
||||||
bytes = bytes.slice(extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
var zeros = 0;
|
|
||||||
|
|
||||||
while (zeros !== input.length && input[zeros] === alphabet[0]) {
|
|
||||||
zeros += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [].concat(utils.arraySet(zeros, 0), bytes);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Base.verify_checksum = function(bytes) {
|
Base.verify_checksum = function(bytes) {
|
||||||
var computed = sha256hash(bytes.slice(0, -4)).slice(0, 4);
|
var computed = sha256(sha256(bytes.slice(0, -4))).slice(0, 4);
|
||||||
var checksum = bytes.slice(-4);
|
var checksum = bytes.slice(-4);
|
||||||
var result = true;
|
return _.isEqual(computed, checksum);
|
||||||
|
|
||||||
for (var i=0; i<4; i++) {
|
|
||||||
if (computed[i] !== checksum[i]) {
|
|
||||||
result = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --> input: Array
|
// --> input: Array
|
||||||
@@ -129,7 +119,7 @@ Base.encode_check = function(version, input, alphabet) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --> input : String
|
// --> input : String
|
||||||
// <-- NaN || BigInteger
|
// <-- NaN || sjcl.bn
|
||||||
Base.decode_check = function(version, input, alphabet) {
|
Base.decode_check = function(version, input, alphabet) {
|
||||||
var buffer = Base.decode(input, alphabet);
|
var buffer = Base.decode(input, alphabet);
|
||||||
|
|
||||||
@@ -143,17 +133,11 @@ Base.decode_check = function(version, input, alphabet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Multiple allowed versions
|
// Multiple allowed versions
|
||||||
if (Array.isArray(version)) {
|
if (Array.isArray(version) && _.every(version, function(v) {
|
||||||
var match = false;
|
return v !== buffer[0];
|
||||||
|
})) {
|
||||||
for (var i=0, l=version.length; i<l; i++) {
|
|
||||||
match |= version[i] === buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return NaN;
|
return NaN;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!Base.verify_checksum(buffer)) {
|
if (!Base.verify_checksum(buffer)) {
|
||||||
return NaN;
|
return NaN;
|
||||||
@@ -163,7 +147,8 @@ Base.decode_check = function(version, input, alphabet) {
|
|||||||
// intrepret the value as a negative number
|
// intrepret the value as a negative number
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
|
|
||||||
return new BigInteger(buffer.slice(0, -4), 256);
|
return sjcl.bn.fromBits(
|
||||||
|
sjcl.codec.bytes.toBits(buffer.slice(0, -4)));
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Base = Base;
|
exports.Base = Base;
|
||||||
|
|||||||
32
src/js/ripple/baseconverter.js
Normal file
32
src/js/ripple/baseconverter.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
function normalize(digitArray) {
|
||||||
|
while (digitArray[0] === 0) {
|
||||||
|
digitArray.shift();
|
||||||
|
}
|
||||||
|
return digitArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
function divmod(digitArray, base, divisor) {
|
||||||
|
var remainder = 0;
|
||||||
|
var quotient = [];
|
||||||
|
for (var j = 0; j < digitArray.length; j++) {
|
||||||
|
var temp = remainder * base + parseInt(digitArray[j], 10);
|
||||||
|
quotient.push(Math.floor(temp / divisor));
|
||||||
|
remainder = temp % divisor;
|
||||||
|
}
|
||||||
|
return {quotient: normalize(quotient), remainder: remainder};
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertBase(digitArray, fromBase, toBase) {
|
||||||
|
var result = [];
|
||||||
|
var dividend = digitArray;
|
||||||
|
while (dividend.length > 0) {
|
||||||
|
var qr = divmod(dividend, fromBase, toBase);
|
||||||
|
result.unshift(qr.remainder);
|
||||||
|
dividend = qr.quotient;
|
||||||
|
}
|
||||||
|
return normalize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = convertBase;
|
||||||
@@ -1,13 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*eslint no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data type map.
|
* Data type map.
|
||||||
*
|
*
|
||||||
* Mapping of type ids to data types. The type id is specified by the high
|
* Mapping of type ids to data types. The type id is specified by the high
|
||||||
*
|
*
|
||||||
* For reference, see rippled's definition:
|
* For reference, see rippled's definition:
|
||||||
* https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol/SField.cpp
|
* https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol
|
||||||
|
* /SField.cpp
|
||||||
*/
|
*/
|
||||||
var TYPES_MAP = exports.types = [
|
|
||||||
void(0),
|
exports.types = [
|
||||||
|
undefined,
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
'Int16', // 1
|
'Int16', // 1
|
||||||
@@ -20,11 +26,11 @@ var TYPES_MAP = exports.types = [
|
|||||||
'Account', // 8
|
'Account', // 8
|
||||||
|
|
||||||
// 9-13 reserved
|
// 9-13 reserved
|
||||||
void(0), // 9
|
undefined, // 9
|
||||||
void(0), // 10
|
undefined, // 10
|
||||||
void(0), // 11
|
undefined, // 11
|
||||||
void(0), // 12
|
undefined, // 12
|
||||||
void(0), // 13
|
undefined, // 13
|
||||||
|
|
||||||
'Object', // 14
|
'Object', // 14
|
||||||
'Array', // 15
|
'Array', // 15
|
||||||
@@ -151,7 +157,7 @@ var FIELDS_MAP = exports.fields = {
|
|||||||
8: 'RegularKey'
|
8: 'RegularKey'
|
||||||
},
|
},
|
||||||
14: { // Object
|
14: { // Object
|
||||||
1: void(0), //end of Object
|
1: undefined, // end of Object
|
||||||
2: 'TransactionMetaData',
|
2: 'TransactionMetaData',
|
||||||
3: 'CreatedNode',
|
3: 'CreatedNode',
|
||||||
4: 'DeletedNode',
|
4: 'DeletedNode',
|
||||||
@@ -163,7 +169,7 @@ var FIELDS_MAP = exports.fields = {
|
|||||||
10: 'Memo'
|
10: 'Memo'
|
||||||
},
|
},
|
||||||
15: { // Array
|
15: { // Array
|
||||||
1: void(0), //end of Array
|
1: undefined, // end of Array
|
||||||
2: 'SigningAccounts',
|
2: 'SigningAccounts',
|
||||||
3: 'TxnSignatures',
|
3: 'TxnSignatures',
|
||||||
4: 'Signatures',
|
4: 'Signatures',
|
||||||
@@ -204,7 +210,6 @@ Object.keys(FIELDS_MAP).forEach(function(k1) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var REQUIRED = exports.REQUIRED = 0,
|
var REQUIRED = exports.REQUIRED = 0,
|
||||||
OPTIONAL = exports.OPTIONAL = 1,
|
OPTIONAL = exports.OPTIONAL = 1,
|
||||||
DEFAULT = exports.DEFAULT = 2;
|
DEFAULT = exports.DEFAULT = 2;
|
||||||
@@ -229,7 +234,9 @@ exports.tx = {
|
|||||||
[ 'WalletSize' , OPTIONAL ],
|
[ 'WalletSize' , OPTIONAL ],
|
||||||
[ 'MessageKey' , OPTIONAL ],
|
[ 'MessageKey' , OPTIONAL ],
|
||||||
[ 'Domain' , OPTIONAL ],
|
[ 'Domain' , OPTIONAL ],
|
||||||
[ 'TransferRate' , OPTIONAL ]
|
[ 'TransferRate' , OPTIONAL ],
|
||||||
|
[ 'SetFlag' , OPTIONAL ],
|
||||||
|
[ 'ClearFlag' , OPTIONAL ]
|
||||||
]),
|
]),
|
||||||
TrustSet: [20].concat(base, [
|
TrustSet: [20].concat(base, [
|
||||||
[ 'LimitAmount' , OPTIONAL ],
|
[ 'LimitAmount' , OPTIONAL ],
|
||||||
@@ -239,13 +246,14 @@ exports.tx = {
|
|||||||
OfferCreate: [7].concat(base, [
|
OfferCreate: [7].concat(base, [
|
||||||
[ 'TakerPays' , REQUIRED ],
|
[ 'TakerPays' , REQUIRED ],
|
||||||
[ 'TakerGets' , REQUIRED ],
|
[ 'TakerGets' , REQUIRED ],
|
||||||
[ 'Expiration' , OPTIONAL ]
|
[ 'Expiration' , OPTIONAL ],
|
||||||
|
[ 'OfferSequence' , OPTIONAL ]
|
||||||
]),
|
]),
|
||||||
OfferCancel: [8].concat(base, [
|
OfferCancel: [8].concat(base, [
|
||||||
[ 'OfferSequence' , REQUIRED ]
|
[ 'OfferSequence' , REQUIRED ]
|
||||||
]),
|
]),
|
||||||
SetRegularKey: [5].concat(base, [
|
SetRegularKey: [5].concat(base, [
|
||||||
[ 'RegularKey' , REQUIRED ]
|
[ 'RegularKey' , OPTIONAL ]
|
||||||
]),
|
]),
|
||||||
Payment: [0].concat(base, [
|
Payment: [0].concat(base, [
|
||||||
[ 'Destination' , REQUIRED ],
|
[ 'Destination' , REQUIRED ],
|
||||||
@@ -271,12 +279,21 @@ exports.tx = {
|
|||||||
EnableFeature: [100].concat(base, [
|
EnableFeature: [100].concat(base, [
|
||||||
[ 'Feature' , REQUIRED ]
|
[ 'Feature' , REQUIRED ]
|
||||||
]),
|
]),
|
||||||
|
EnableAmendment: [100].concat(base, [
|
||||||
|
[ 'Amendment' , REQUIRED ]
|
||||||
|
]),
|
||||||
SetFee: [101].concat(base, [
|
SetFee: [101].concat(base, [
|
||||||
[ 'Features' , REQUIRED ],
|
|
||||||
[ 'BaseFee' , REQUIRED ],
|
[ 'BaseFee' , REQUIRED ],
|
||||||
[ 'ReferenceFeeUnits' , REQUIRED ],
|
[ 'ReferenceFeeUnits' , REQUIRED ],
|
||||||
[ 'ReserveBase' , REQUIRED ],
|
[ 'ReserveBase' , REQUIRED ],
|
||||||
[ 'ReserveIncrement' , REQUIRED ]
|
[ 'ReserveIncrement' , REQUIRED ]
|
||||||
|
]),
|
||||||
|
TicketCreate: [10].concat(base, [
|
||||||
|
[ 'Target' , OPTIONAL ],
|
||||||
|
[ 'Expiration' , OPTIONAL ]
|
||||||
|
]),
|
||||||
|
TicketCancel: [11].concat(base, [
|
||||||
|
[ 'TicketID' , REQUIRED ]
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -414,5 +431,8 @@ exports.ter = {
|
|||||||
tecNO_TARGET : 138,
|
tecNO_TARGET : 138,
|
||||||
tecNO_PERMISSION : 139,
|
tecNO_PERMISSION : 139,
|
||||||
tecNO_ENTRY : 140,
|
tecNO_ENTRY : 140,
|
||||||
tecINSUFFICIENT_RESERVE : 141
|
tecINSUFFICIENT_RESERVE : 141,
|
||||||
|
tecNEED_MASTER_KEY : 142,
|
||||||
|
tecDST_TAG_NEEDED : 143,
|
||||||
|
tecINTERNAL : 144
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
var UInt160 = require('./uint160').UInt160;
|
var UInt160 = require('./uint160').UInt160;
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
@@ -17,7 +19,6 @@ var Currency = extend(function() {
|
|||||||
// XXX Should support hex, C++ doesn't currently allow it.
|
// XXX Should support hex, C++ doesn't currently allow it.
|
||||||
|
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
|
|
||||||
this._update();
|
this._update();
|
||||||
}, UInt160);
|
}, UInt160);
|
||||||
|
|
||||||
@@ -32,25 +33,37 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
|
|||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* USD => currency
|
* USD => currency
|
||||||
* USD - Dollar => currency with optional full currency name
|
* USD - Dollar => currency with optional full currency
|
||||||
* XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate per year
|
* name
|
||||||
|
* XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate
|
||||||
|
* per year
|
||||||
* XAU - Gold (-0.5%pa) => Optionally allowed full currency name
|
* XAU - Gold (-0.5%pa) => Optionally allowed full currency name
|
||||||
* USD (1%pa) => US dollars with 1% effective interest per year
|
* USD (1%pa) => US dollars with 1% effective interest
|
||||||
|
* per year
|
||||||
* INR - Indian Rupees => Optional full currency name with spaces
|
* INR - Indian Rupees => Optional full currency name with spaces
|
||||||
* TYX - 30-Year Treasuries => Optional full currency with numbers and a dash
|
* TYX - 30-Year Treasuries => Optional full currency with numbers
|
||||||
* TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers, dash and interest rate
|
* and a dash
|
||||||
|
* TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers,
|
||||||
|
* dash and interest rate
|
||||||
*
|
*
|
||||||
* The regular expression below matches above cases, broken down for better understanding:
|
* The regular expression below matches above cases, broken down for better
|
||||||
|
* understanding:
|
||||||
*
|
*
|
||||||
* ^\s* // start with any amount of whitespace
|
* ^\s* // start with any amount of whitespace
|
||||||
* ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
|
* ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3
|
||||||
* (\s*-\s*[- \w]+) // optional full currency name following the dash after currency code,
|
* digit numeric currency-code. See ISO 4217
|
||||||
* full currency code can contain letters, numbers and dashes
|
* (\s*-\s*[- \w]+) // optional full currency name following the dash
|
||||||
* (\s*\(-?\d+\.?\d*%pa\))? // optional demurrage rate, has optional - and . notation (-0.5%pa)
|
* after currency code, full currency code can
|
||||||
|
* contain letters, numbers and dashes
|
||||||
|
* (\s*\(-?\d+\.?\d*%pa\))? // optional demurrage rate, has optional - and
|
||||||
|
* . notation (-0.5%pa)
|
||||||
* \s*$ // end with any amount of whitespace
|
* \s*$ // end with any amount of whitespace
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
|
|
||||||
|
/*eslint-disable max-len*/
|
||||||
|
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9\<\>\(\)\{\}\[\]\|\?\!\@\#\$\%\^\&]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
|
||||||
|
/*eslint-enable max-len*/
|
||||||
|
|
||||||
Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
||||||
return (new Currency()).parse_json(j, shouldInterpretXrpAsIou);
|
return (new Currency()).parse_json(j, shouldInterpretXrpAsIou);
|
||||||
@@ -58,39 +71,65 @@ Currency.from_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
|
|
||||||
Currency.from_human = function(j, opts) {
|
Currency.from_human = function(j, opts) {
|
||||||
return (new Currency().parse_human(j, opts));
|
return (new Currency().parse_human(j, opts));
|
||||||
}
|
};
|
||||||
|
|
||||||
// this._value = NaN on error.
|
// this._value = NaN on error.
|
||||||
Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
|
|
||||||
switch (typeof j) {
|
if (j instanceof Currency) {
|
||||||
case 'string':
|
this._value = j.copyTo({})._value;
|
||||||
|
this._update();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// if an empty string is given, fall back to XRP
|
switch (typeof j) {
|
||||||
|
case 'number':
|
||||||
|
if (!isNaN(j)) {
|
||||||
|
this.parse_number(j);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
if (!j || j === '0') {
|
if (!j || j === '0') {
|
||||||
this.parse_hex(shouldInterpretXrpAsIou ? Currency.HEX_CURRENCY_BAD : Currency.HEX_ZERO);
|
// Empty string or XRP
|
||||||
|
this.parse_hex(shouldInterpretXrpAsIou
|
||||||
|
? Currency.HEX_CURRENCY_BAD
|
||||||
|
: Currency.HEX_ZERO);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j === '1') {
|
||||||
|
// 'no currency'
|
||||||
|
this.parse_hex(Currency.HEX_ONE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^[A-F0-9]{40}$/.test(j)) {
|
||||||
|
// Hex format
|
||||||
|
this.parse_hex(j);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// match the given string to see if it's in an allowed format
|
// match the given string to see if it's in an allowed format
|
||||||
var matches = String(j).match(this.human_RE);
|
var matches = j.match(this.human_RE);
|
||||||
|
|
||||||
if (matches) {
|
if (matches) {
|
||||||
|
|
||||||
var currencyCode = matches[1];
|
var currencyCode = matches[1];
|
||||||
|
|
||||||
// for the currency 'XRP' case
|
// for the currency 'XRP' case
|
||||||
// we drop everything else that could have been provided
|
// we drop everything else that could have been provided
|
||||||
// e.g. 'XRP - Ripple'
|
// e.g. 'XRP - Ripple'
|
||||||
if (!currencyCode || /^(0|XRP)$/.test(currencyCode)) {
|
if (!currencyCode || /^(0|XRP)$/.test(currencyCode)) {
|
||||||
this.parse_hex(shouldInterpretXrpAsIou ? Currency.HEX_CURRENCY_BAD : Currency.HEX_ZERO);
|
this.parse_hex(shouldInterpretXrpAsIou
|
||||||
|
? Currency.HEX_CURRENCY_BAD
|
||||||
|
: Currency.HEX_ZERO);
|
||||||
|
|
||||||
// early break, we can't have interest on XRP
|
// early break, we can't have interest on XRP
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the full currency is matched as it is part of the valid currency format, but not stored
|
// the full currency is matched as it is part of the valid currency
|
||||||
|
// format, but not stored
|
||||||
// var full_currency = matches[2] || '';
|
// var full_currency = matches[2] || '';
|
||||||
var interest = matches[3] || '';
|
var interest = matches[3] || '';
|
||||||
|
|
||||||
@@ -117,12 +156,14 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
currencyData[2] = currencyCode.charCodeAt(1) & 0xff;
|
currencyData[2] = currencyCode.charCodeAt(1) & 0xff;
|
||||||
currencyData[3] = currencyCode.charCodeAt(2) & 0xff;
|
currencyData[3] = currencyCode.charCodeAt(2) & 0xff;
|
||||||
|
|
||||||
// byte 5-8 are for reference date, but should always be 0 so we won't fill it
|
// byte 5-8 are for reference date, but should always be 0 so we
|
||||||
|
// won't fill it
|
||||||
|
|
||||||
// byte 9-16 are for the interest
|
// byte 9-16 are for the interest
|
||||||
percentage = parseFloat(percentage[0]);
|
percentage = parseFloat(percentage[0]);
|
||||||
|
|
||||||
// the interest or demurrage is expressed as a yearly (per annum) value
|
// the interest or demurrage is expressed as a yearly (per annum)
|
||||||
|
// value
|
||||||
var secondsPerYear = 31536000; // 60 * 60 * 24 * 365
|
var secondsPerYear = 31536000; // 60 * 60 * 24 * 365
|
||||||
|
|
||||||
// Calculating the interest e-fold
|
// Calculating the interest e-fold
|
||||||
@@ -135,7 +176,8 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
currencyData[8 + i] = bytes[i] & 0xff;
|
currencyData[8 + i] = bytes[i] & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the last 4 bytes are reserved for future use, so we won't fill those
|
// the last 4 bytes are reserved for future use, so we won't fill
|
||||||
|
// those
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
currencyData[12] = currencyCode.charCodeAt(0) & 0xff;
|
currencyData[12] = currencyCode.charCodeAt(0) & 0xff;
|
||||||
@@ -144,21 +186,6 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.parse_bytes(currencyData);
|
this.parse_bytes(currencyData);
|
||||||
} else {
|
|
||||||
this.parse_hex(j);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'number':
|
|
||||||
if (!isNaN(j)) {
|
|
||||||
this.parse_number(j);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'object':
|
|
||||||
if (j instanceof Currency) {
|
|
||||||
this._value = j.copyTo({})._value;
|
|
||||||
this._update();
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -166,7 +193,6 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Currency.prototype.parse_human = function(j) {
|
Currency.prototype.parse_human = function(j) {
|
||||||
return this.parse_json(j);
|
return this.parse_json(j);
|
||||||
};
|
};
|
||||||
@@ -176,6 +202,7 @@ Currency.prototype.parse_human = function(j) {
|
|||||||
*
|
*
|
||||||
* You should never need to call this.
|
* You should never need to call this.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Currency.prototype._update = function() {
|
Currency.prototype._update = function() {
|
||||||
var bytes = this.to_bytes();
|
var bytes = this.to_bytes();
|
||||||
|
|
||||||
@@ -183,7 +210,7 @@ Currency.prototype._update = function() {
|
|||||||
var isZeroExceptInStandardPositions = true;
|
var isZeroExceptInStandardPositions = true;
|
||||||
|
|
||||||
if (!bytes) {
|
if (!bytes) {
|
||||||
return 'XRP';
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._native = false;
|
this._native = false;
|
||||||
@@ -193,7 +220,8 @@ Currency.prototype._update = function() {
|
|||||||
this._iso_code = '';
|
this._iso_code = '';
|
||||||
|
|
||||||
for (var i = 0; i < 20; i++) {
|
for (var i = 0; i < 20; i++) {
|
||||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || bytes[i]===0);
|
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
|
||||||
|
&& (i === 12 || i === 13 || i === 14 || bytes[i] === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isZeroExceptInStandardPositions) {
|
if (isZeroExceptInStandardPositions) {
|
||||||
@@ -201,7 +229,7 @@ Currency.prototype._update = function() {
|
|||||||
+ String.fromCharCode(bytes[13])
|
+ String.fromCharCode(bytes[13])
|
||||||
+ String.fromCharCode(bytes[14]);
|
+ String.fromCharCode(bytes[14]);
|
||||||
|
|
||||||
if (this._iso_code === '\0\0\0') {
|
if (this._iso_code === '\u0000\u0000\u0000') {
|
||||||
this._native = true;
|
this._native = true;
|
||||||
this._iso_code = 'XRP';
|
this._iso_code = 'XRP';
|
||||||
}
|
}
|
||||||
@@ -230,7 +258,8 @@ Currency.prototype.parse_bytes = function(byte_array) {
|
|||||||
var isZeroExceptInStandardPositions = true;
|
var isZeroExceptInStandardPositions = true;
|
||||||
|
|
||||||
for (var i=0; i<20; i++) {
|
for (var i=0; i<20; i++) {
|
||||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || byte_array[0]===0)
|
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
|
||||||
|
&& (i===12 || i===13 || i===14 || byte_array[0]===0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isZeroExceptInStandardPositions) {
|
if (isZeroExceptInStandardPositions) {
|
||||||
@@ -260,20 +289,25 @@ Currency.prototype.is_native = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this currency is an interest-bearing/demurring currency.
|
* @return {Boolean} whether this currency is an interest-bearing currency
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Currency.prototype.has_interest = function() {
|
Currency.prototype.has_interest = function() {
|
||||||
return this._type === 1 && !isNaN(this._interest_start) && !isNaN(this._interest_period);
|
return this._type === 1
|
||||||
|
&& !isNaN(this._interest_start)
|
||||||
|
&& !isNaN(this._interest_period);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param referenceDate - number of seconds since the Ripple Epoch (0:00 on January 1, 2000 UTC)
|
* @param {number} referenceDate number of seconds since the Ripple Epoch
|
||||||
* used to calculate the interest over provided interval
|
* (0:00 on January 1, 2000 UTC) used to calculate the
|
||||||
* pass in one years worth of seconds to ge the yearly interest
|
* interest over provided interval pass in one years
|
||||||
* @returns {number} - interest for provided interval, can be negative for demurred currencies
|
* worth of seconds to ge the yearly interest
|
||||||
|
* @returns {number} interest for provided interval, can be negative for
|
||||||
|
* demurred currencies
|
||||||
*/
|
*/
|
||||||
Currency.prototype.get_interest_at = function(referenceDate, decimals) {
|
Currency.prototype.get_interest_at = function(referenceDate) {
|
||||||
if (!this.has_interest()) {
|
if (!this.has_interest()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -288,14 +322,16 @@ Currency.prototype.get_interest_at = function(referenceDate, decimals) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// calculate interest by e-fold number
|
// calculate interest by e-fold number
|
||||||
return Math.exp((referenceDate - this._interest_start) / this._interest_period);
|
return Math.exp((referenceDate - this._interest_start)
|
||||||
|
/ this._interest_period);
|
||||||
};
|
};
|
||||||
|
|
||||||
Currency.prototype.get_interest_percentage_at = function(referenceDate, decimals) {
|
Currency.prototype.get_interest_percentage_at
|
||||||
|
= function(referenceDate, decimals) {
|
||||||
var interest = this.get_interest_at(referenceDate, decimals);
|
var interest = this.get_interest_at(referenceDate, decimals);
|
||||||
|
|
||||||
// convert to percentage
|
// convert to percentage
|
||||||
var interest = (interest*100)-100;
|
interest = (interest * 100) - 100;
|
||||||
var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
|
var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
|
||||||
|
|
||||||
// round to two decimals behind the dot
|
// round to two decimals behind the dot
|
||||||
@@ -308,7 +344,7 @@ Currency.prototype.get_interest_percentage_at = function(referenceDate, decimals
|
|||||||
// currency data, since there are some values that are invalid.
|
// currency data, since there are some values that are invalid.
|
||||||
//
|
//
|
||||||
// Currency.prototype.is_valid = function() {
|
// Currency.prototype.is_valid = function() {
|
||||||
// return this._value instanceof BigInteger && ...;
|
// return UInt.prototype.is_valid() && ...;
|
||||||
// };
|
// };
|
||||||
|
|
||||||
Currency.prototype.to_json = function(opts) {
|
Currency.prototype.to_json = function(opts) {
|
||||||
@@ -317,27 +353,34 @@ Currency.prototype.to_json = function(opts) {
|
|||||||
return 'XRP';
|
return 'XRP';
|
||||||
}
|
}
|
||||||
|
|
||||||
var opts = opts || {};
|
if (!opts) {
|
||||||
|
opts = {};
|
||||||
|
}
|
||||||
|
|
||||||
var currency;
|
var currency;
|
||||||
var fullName = opts && opts.full_name ? ' - ' + opts.full_name : '';
|
var fullName = opts && opts.full_name ? ' - ' + opts.full_name : '';
|
||||||
opts.show_interest = opts.show_interest !== void(0) ? opts.show_interest : this.has_interest();
|
opts.show_interest = opts.show_interest !== undefined
|
||||||
|
? opts.show_interest
|
||||||
|
: this.has_interest();
|
||||||
|
|
||||||
if (!opts.force_hex && /^[A-Z0-9]{3}$/.test(this._iso_code)) {
|
if (!opts.force_hex && /^[A-Z0-9]{3}$/.test(this._iso_code)) {
|
||||||
currency = this._iso_code + fullName;
|
currency = this._iso_code + fullName;
|
||||||
if (opts.show_interest) {
|
if (opts.show_interest) {
|
||||||
var decimals = !isNaN(opts.decimals) ? opts.decimals : void(0);
|
var decimals = !isNaN(opts.decimals) ? opts.decimals : undefined;
|
||||||
var interestPercentage = this.has_interest() ? this.get_interest_percentage_at(this._interest_start + 3600 * 24 * 365, decimals) : 0;
|
var interestPercentage = this.has_interest()
|
||||||
|
? this.get_interest_percentage_at(
|
||||||
|
this._interest_start + 3600 * 24 * 365, decimals
|
||||||
|
)
|
||||||
|
: 0;
|
||||||
currency += ' (' + interestPercentage + '%pa)';
|
currency += ' (' + interestPercentage + '%pa)';
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Fallback to returning the raw currency hex
|
// Fallback to returning the raw currency hex
|
||||||
currency = this.to_hex();
|
currency = this.to_hex();
|
||||||
|
|
||||||
// XXX This is to maintain backwards compatibility, but it is very, very odd
|
// XXX This is to maintain backwards compatibility, but it is very, very
|
||||||
// behavior, so we should deprecate it and get rid of it as soon as
|
// odd behavior, so we should deprecate it and get rid of it as soon as
|
||||||
// possible.
|
// possible.
|
||||||
if (currency === Currency.HEX_ONE) {
|
if (currency === Currency.HEX_ONE) {
|
||||||
currency = 1;
|
currency = 1;
|
||||||
@@ -357,5 +400,3 @@ Currency.prototype.get_iso = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.Currency = Currency;
|
exports.Currency = Currency;
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
'use strict';
|
||||||
exports.Remote = require('./remote').Remote;
|
exports.Remote = require('./remote').Remote;
|
||||||
exports.Request = require('./request').Request;
|
exports.Request = require('./request').Request;
|
||||||
exports.Amount = require('./amount').Amount;
|
exports.Amount = require('./amount').Amount;
|
||||||
@@ -5,6 +6,7 @@ exports.Account = require('./account').Account;
|
|||||||
exports.Transaction = require('./transaction').Transaction;
|
exports.Transaction = require('./transaction').Transaction;
|
||||||
exports.Currency = require('./currency').Currency;
|
exports.Currency = require('./currency').Currency;
|
||||||
exports.Base = require('./base').Base;
|
exports.Base = require('./base').Base;
|
||||||
|
exports.UInt128 = require('./uint128').UInt128;
|
||||||
exports.UInt160 = require('./uint160').UInt160;
|
exports.UInt160 = require('./uint160').UInt160;
|
||||||
exports.UInt256 = require('./uint256').UInt256;
|
exports.UInt256 = require('./uint256').UInt256;
|
||||||
exports.Seed = require('./seed').Seed;
|
exports.Seed = require('./seed').Seed;
|
||||||
@@ -12,13 +14,14 @@ exports.Meta = require('./meta').Meta;
|
|||||||
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
||||||
exports.RippleError = require('./rippleerror').RippleError;
|
exports.RippleError = require('./rippleerror').RippleError;
|
||||||
exports.Message = require('./message').Message;
|
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.binformat = require('./binformat');
|
||||||
exports.utils = require('./utils');
|
exports.utils = require('./utils');
|
||||||
exports.Server = require('./server').Server;
|
exports.Server = require('./server').Server;
|
||||||
exports.Wallet = require('./wallet');
|
exports.Wallet = require('./wallet');
|
||||||
|
exports.Ledger = require('./ledger').Ledger;
|
||||||
|
exports.TransactionQueue = require('./transactionqueue').TransactionQueue;
|
||||||
|
exports.RangeSet = require('./rangeset').RangeSet;
|
||||||
|
exports.convertBase = require('./baseconverter');
|
||||||
|
|
||||||
// Important: We do not guarantee any specific version of SJCL or for any
|
// 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
|
// specific features to be included. The version and configuration may change at
|
||||||
@@ -28,12 +31,13 @@ exports.Wallet = require('./wallet');
|
|||||||
// the official client, it makes sense to expose the SJCL instance so we don't
|
// the official client, it makes sense to expose the SJCL instance so we don't
|
||||||
// have to include it twice.
|
// have to include it twice.
|
||||||
exports.sjcl = require('./utils').sjcl;
|
exports.sjcl = require('./utils').sjcl;
|
||||||
|
exports.types = require('./serializedtypes');
|
||||||
|
|
||||||
exports.config = require('./config');
|
exports.config = require('./config');
|
||||||
|
|
||||||
// camelCase to under_scored API conversion
|
// camelCase to under_scored API conversion
|
||||||
function attachUnderscored(c) {
|
function attachUnderscored(name) {
|
||||||
var o = exports[c];
|
var o = exports[name];
|
||||||
|
|
||||||
Object.keys(o.prototype).forEach(function(key) {
|
Object.keys(o.prototype).forEach(function(key) {
|
||||||
var UPPERCASE = /([A-Z]{1})[a-z]+/g;
|
var UPPERCASE = /([A-Z]{1})[a-z]+/g;
|
||||||
@@ -48,7 +52,7 @@ function attachUnderscored(c) {
|
|||||||
|
|
||||||
o.prototype[underscored] = o.prototype[key];
|
o.prototype[underscored] = o.prototype[key];
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
['Remote',
|
['Remote',
|
||||||
'Request',
|
'Request',
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*eslint new-cap: 1*/
|
||||||
|
|
||||||
var sjcl = require('./utils').sjcl;
|
var sjcl = require('./utils').sjcl;
|
||||||
|
|
||||||
var UInt160 = require('./uint160').UInt160;
|
var UInt160 = require('./uint160').UInt160;
|
||||||
@@ -8,7 +12,7 @@ function KeyPair() {
|
|||||||
this._curve = sjcl.ecc.curves.k256;
|
this._curve = sjcl.ecc.curves.k256;
|
||||||
this._secret = null;
|
this._secret = null;
|
||||||
this._pubkey = null;
|
this._pubkey = null;
|
||||||
};
|
}
|
||||||
|
|
||||||
KeyPair.from_bn_secret = function(j) {
|
KeyPair.from_bn_secret = function(j) {
|
||||||
return (j instanceof this) ? j.clone() : (new this()).parse_bn_secret(j);
|
return (j instanceof this) ? j.clone() : (new this()).parse_bn_secret(j);
|
||||||
@@ -20,15 +24,16 @@ KeyPair.prototype.parse_bn_secret = function(j) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns public key as sjcl public key.
|
|
||||||
*
|
|
||||||
* @private
|
* @private
|
||||||
|
*
|
||||||
|
* @return {sjcl.ecc.ecdsa.publicKey} public key
|
||||||
*/
|
*/
|
||||||
KeyPair.prototype._pub = function() {
|
KeyPair.prototype._pub = function() {
|
||||||
var curve = this._curve;
|
var curve = this._curve;
|
||||||
|
|
||||||
if (!this._pubkey && this._secret) {
|
if (!this._pubkey && this._secret) {
|
||||||
var exponent = this._secret._exponent;
|
var exponent = this._secret._exponent;
|
||||||
|
|
||||||
this._pubkey = new sjcl.ecc.ecdsa.publicKey(curve, curve.G.mult(exponent));
|
this._pubkey = new sjcl.ecc.ecdsa.publicKey(curve, curve.G.mult(exponent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,9 +41,9 @@ KeyPair.prototype._pub = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns public key in compressed format as bit array.
|
|
||||||
*
|
|
||||||
* @private
|
* @private
|
||||||
|
*
|
||||||
|
* @return {sjcl.bitArray} public key bits in compressed form
|
||||||
*/
|
*/
|
||||||
KeyPair.prototype._pub_bits = function() {
|
KeyPair.prototype._pub_bits = function() {
|
||||||
var pub = this._pub();
|
var pub = this._pub();
|
||||||
@@ -56,9 +61,7 @@ KeyPair.prototype._pub_bits = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns public key as hex.
|
* @return {String} public key bytes in compressed form, hex encoded.
|
||||||
*
|
|
||||||
* Key will be returned as a compressed pubkey - 33 bytes converted to hex.
|
|
||||||
*/
|
*/
|
||||||
KeyPair.prototype.to_hex_pub = function() {
|
KeyPair.prototype.to_hex_pub = function() {
|
||||||
var bits = this._pub_bits();
|
var bits = this._pub_bits();
|
||||||
@@ -70,7 +73,7 @@ KeyPair.prototype.to_hex_pub = function() {
|
|||||||
return sjcl.codec.hex.fromBits(bits).toUpperCase();
|
return sjcl.codec.hex.fromBits(bits).toUpperCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
function SHA256_RIPEMD160(bits) {
|
function sha256_ripemd160(bits) {
|
||||||
return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
|
return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +84,7 @@ KeyPair.prototype.get_address = function() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hash = SHA256_RIPEMD160(bits);
|
var hash = sha256_ripemd160(bits);
|
||||||
|
|
||||||
var address = UInt160.from_bits(hash);
|
var address = UInt160.from_bits(hash);
|
||||||
address.set_version(Base.VER_ACCOUNT_ID);
|
address.set_version(Base.VER_ACCOUNT_ID);
|
||||||
@@ -89,8 +92,9 @@ KeyPair.prototype.get_address = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
KeyPair.prototype.sign = function(hash) {
|
KeyPair.prototype.sign = function(hash) {
|
||||||
|
var PARANOIA_256_BITS = 6; // sjcl constant for ensuring 256 bits of entropy
|
||||||
hash = UInt256.from_json(hash);
|
hash = UInt256.from_json(hash);
|
||||||
var sig = this._secret.sign(hash.to_bits(), 0);
|
var sig = this._secret.sign(hash.to_bits(), PARANOIA_256_BITS);
|
||||||
sig = this._secret.canonicalizeSignature(sig);
|
sig = this._secret.canonicalizeSignature(sig);
|
||||||
return this._secret.encodeDER(sig);
|
return this._secret.encodeDER(sig);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logging functionality for ripple-lib and any applications built on it.
|
* Logging functionality for ripple-lib and any applications built on it.
|
||||||
|
*
|
||||||
|
* @param {String} namespace logging prefix
|
||||||
|
* @return {Void} this function does not return...
|
||||||
*/
|
*/
|
||||||
function Log(namespace) {
|
function Log(namespace) {
|
||||||
if (!namespace) {
|
if (!namespace) {
|
||||||
@@ -7,11 +12,11 @@ function Log(namespace) {
|
|||||||
} else if (Array.isArray(namespace)) {
|
} else if (Array.isArray(namespace)) {
|
||||||
this._namespace = namespace;
|
this._namespace = namespace;
|
||||||
} else {
|
} else {
|
||||||
this._namespace = [''+namespace];
|
this._namespace = [String(namespace)];
|
||||||
}
|
}
|
||||||
|
|
||||||
this._prefix = this._namespace.concat(['']).join(': ');
|
this._prefix = this._namespace.concat(['']).join(': ');
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a sub-logger.
|
* Create a sub-logger.
|
||||||
@@ -24,6 +29,9 @@ function Log(namespace) {
|
|||||||
*
|
*
|
||||||
* log.info('connection successful');
|
* log.info('connection successful');
|
||||||
* // prints: 'server: connection successful'
|
* // prints: 'server: connection successful'
|
||||||
|
*
|
||||||
|
* @param {String} namespace logging prefix
|
||||||
|
* @return {Log} sub logger
|
||||||
*/
|
*/
|
||||||
Log.prototype.sub = function(namespace) {
|
Log.prototype.sub = function(namespace) {
|
||||||
var subNamespace = this._namespace.slice();
|
var subNamespace = this._namespace.slice();
|
||||||
@@ -43,9 +51,9 @@ Log.prototype._setParent = function(parentLogger) {
|
|||||||
|
|
||||||
Log.makeLevel = function(level) {
|
Log.makeLevel = function(level) {
|
||||||
return function() {
|
return function() {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.apply(arguments);
|
||||||
args[0] = this._prefix + args[0];
|
args[0] = this._prefix + args[0];
|
||||||
Log.engine.logObject.apply(Log, args);
|
Log.engine.logObject.apply(Log, [level].concat(args[0], [args.slice(2)]));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,6 +62,46 @@ Log.prototype.info = Log.makeLevel(2);
|
|||||||
Log.prototype.warn = Log.makeLevel(3);
|
Log.prototype.warn = Log.makeLevel(3);
|
||||||
Log.prototype.error = Log.makeLevel(4);
|
Log.prototype.error = Log.makeLevel(4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} message
|
||||||
|
* @param {Array} details
|
||||||
|
* @return {Array} prepared log info
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getLogInfo(message, args) {
|
||||||
|
var stack = new Error().stack;
|
||||||
|
|
||||||
|
return [
|
||||||
|
// Timestamp
|
||||||
|
'[' + new Date().toISOString() + ']',
|
||||||
|
message,
|
||||||
|
'--',
|
||||||
|
// Location
|
||||||
|
(typeof stack === 'string') ? stack.split('\n')[4].replace(/^\s+/, '') : '',
|
||||||
|
'\n'
|
||||||
|
].concat(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Number} log level
|
||||||
|
* @param {Array} log info
|
||||||
|
*/
|
||||||
|
|
||||||
|
function logMessage(logLevel, args) {
|
||||||
|
switch (logLevel) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
console.log.apply(console, args);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
console.warn.apply(console, args);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
console.error.apply(console, args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic logging connector.
|
* Basic logging connector.
|
||||||
*
|
*
|
||||||
@@ -61,20 +109,33 @@ Log.prototype.error = Log.makeLevel(4);
|
|||||||
* implementations. This is the logging engine used in Node.js.
|
* implementations. This is the logging engine used in Node.js.
|
||||||
*/
|
*/
|
||||||
var BasicLogEngine = {
|
var BasicLogEngine = {
|
||||||
logObject: function logObject(msg) {
|
logObject: function logObject(level, message, args) {
|
||||||
var args = Array.prototype.slice.call(arguments, 1);
|
|
||||||
|
|
||||||
args = args.map(function(arg) {
|
args = args.map(function(arg) {
|
||||||
return JSON.stringify(arg, null, 2);
|
return JSON.stringify(arg, null, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
args.unshift(msg);
|
logMessage(level, getLogInfo(message, args));
|
||||||
args.unshift('[' + new Date().toISOString() + ']');
|
|
||||||
|
|
||||||
console.log.apply(console, args);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log engine for browser consoles.
|
||||||
|
*
|
||||||
|
* Browsers tend to have better consoles that support nicely formatted
|
||||||
|
* JavaScript objects. This connector passes objects through to the logging
|
||||||
|
* function without any stringification.
|
||||||
|
*/
|
||||||
|
var InteractiveLogEngine = {
|
||||||
|
logObject: function(level, message, args) {
|
||||||
|
args = args.map(function(arg) {
|
||||||
|
return /MSIE/.test(navigator.userAgent)
|
||||||
|
? JSON.stringify(arg, null, 2)
|
||||||
|
: arg;
|
||||||
|
});
|
||||||
|
|
||||||
|
logMessage(level, getLogInfo(message, args));
|
||||||
|
}
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Null logging connector.
|
* Null logging connector.
|
||||||
*
|
*
|
||||||
@@ -85,10 +146,12 @@ var NullLogEngine = {
|
|||||||
logObject: function() {}
|
logObject: function() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Log.engine = NullLogEngine;
|
if (typeof window !== 'undefined' && typeof console !== 'undefined') {
|
||||||
|
Log.engine = InteractiveLogEngine;
|
||||||
if (console && console.log) {
|
} else if (typeof console !== 'undefined' && console.log) {
|
||||||
Log.engine = BasicLogEngine;
|
Log.engine = BasicLogEngine;
|
||||||
|
} else {
|
||||||
|
Log.engine = NullLogEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
var exports = module.exports = require('./log.js');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log engine for browser consoles.
|
|
||||||
*
|
|
||||||
* Browsers tend to have better consoles that support nicely formatted
|
|
||||||
* JavaScript objects. This connector passes objects through to the logging
|
|
||||||
* function without any stringification.
|
|
||||||
*/
|
|
||||||
var InteractiveLogEngine = {
|
|
||||||
logObject: function (msg, obj) {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 1);
|
|
||||||
|
|
||||||
args = args.map(function(arg) {
|
|
||||||
if (/MSIE/.test(navigator.userAgent)) {
|
|
||||||
return JSON.stringify(arg, null, 2);
|
|
||||||
} else {
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
args.unshift(msg);
|
|
||||||
args.unshift('[' + new Date().toISOString() + ']');
|
|
||||||
|
|
||||||
console.log.apply(console, args);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (window.console && window.console.log) {
|
|
||||||
exports.Log.engine = InteractiveLogEngine;
|
|
||||||
}
|
|
||||||
@@ -26,28 +26,37 @@ function Meta(data) {
|
|||||||
data.AffectedNodes.forEach(this.addNode, this);
|
data.AffectedNodes.forEach(this.addNode, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
Meta.nodeTypes = [
|
Meta.NODE_TYPES = [
|
||||||
'CreatedNode',
|
'CreatedNode',
|
||||||
'ModifiedNode',
|
'ModifiedNode',
|
||||||
'DeletedNode'
|
'DeletedNode'
|
||||||
];
|
];
|
||||||
|
|
||||||
Meta.amountFieldsAffectingIssuer = [
|
Meta.AMOUNT_FIELDS_AFFECTING_ISSUER = [
|
||||||
'LowLimit',
|
'LowLimit',
|
||||||
'HighLimit',
|
'HighLimit',
|
||||||
'TakerPays',
|
'TakerPays',
|
||||||
'TakerGets'
|
'TakerGets'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Meta.ACCOUNT_FIELDS = [
|
||||||
|
'Account',
|
||||||
|
'Owner',
|
||||||
|
'Destination',
|
||||||
|
'Issuer',
|
||||||
|
'Target'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {Object} node
|
||||||
* @api private
|
* @api private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Meta.prototype.getNodeType = function(node) {
|
Meta.prototype.getNodeType = function(node) {
|
||||||
var result = null;
|
var result = null;
|
||||||
|
|
||||||
for (var i=0; i<Meta.nodeTypes.length; i++) {
|
for (var i=0; i<Meta.NODE_TYPES.length; i++) {
|
||||||
var type = Meta.nodeTypes[i];
|
var type = Meta.NODE_TYPES[i];
|
||||||
if (node.hasOwnProperty(type)) {
|
if (node.hasOwnProperty(type)) {
|
||||||
result = type;
|
result = type;
|
||||||
break;
|
break;
|
||||||
@@ -57,6 +66,15 @@ Meta.prototype.getNodeType = function(node) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} field
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Meta.prototype.isAccountField = function(field) {
|
||||||
|
return Meta.ACCOUNT_FIELDS.indexOf(field) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add node to metadata
|
* Add node to metadata
|
||||||
*
|
*
|
||||||
@@ -72,7 +90,6 @@ Meta.prototype.addNode = function(node) {
|
|||||||
|
|
||||||
if ((result.nodeType = this.getNodeType(node))) {
|
if ((result.nodeType = this.getNodeType(node))) {
|
||||||
node = node[result.nodeType];
|
node = node[result.nodeType];
|
||||||
|
|
||||||
result.diffType = result.nodeType;
|
result.diffType = result.nodeType;
|
||||||
result.entryType = node.LedgerEntryType;
|
result.entryType = node.LedgerEntryType;
|
||||||
result.ledgerIndex = node.LedgerIndex;
|
result.ledgerIndex = node.LedgerIndex;
|
||||||
@@ -114,57 +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) {
|
Meta.prototype.getAffectedAccounts = function(from) {
|
||||||
if (this._affectedAccounts) {
|
if (this._affectedAccounts) {
|
||||||
return this._affectedAccounts;
|
return this._affectedAccounts;
|
||||||
@@ -176,12 +142,16 @@ Meta.prototype.getAffectedAccounts = function(from) {
|
|||||||
// TransactionMetaSet::getAffectedAccounts
|
// TransactionMetaSet::getAffectedAccounts
|
||||||
for (var i=0; i<this.nodes.length; i++) {
|
for (var i=0; i<this.nodes.length; i++) {
|
||||||
var node = this.nodes[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) {
|
for (var fieldName in fields) {
|
||||||
var field = fields[fieldName];
|
var field = fields[fieldName];
|
||||||
if (typeof field === 'string' && UInt160.is_valid(field)) {
|
|
||||||
|
if (this.isAccountField(fieldName) && UInt160.is_valid(field)) {
|
||||||
accounts.push(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 amount = Amount.from_json(field);
|
||||||
var issuer = amount.issuer();
|
var issuer = amount.issuer();
|
||||||
if (issuer.is_valid() && !issuer.is_zero()) {
|
if (issuer.is_valid() && !issuer.is_zero()) {
|
||||||
@@ -238,4 +208,53 @@ Meta.prototype.getAffectedBooks = function() {
|
|||||||
return this._affectedBooks;
|
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;
|
exports.Meta = Meta;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -35,28 +35,27 @@ util.inherits(PathFind, EventEmitter);
|
|||||||
PathFind.prototype.create = function () {
|
PathFind.prototype.create = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var req = this.remote.request_path_find_create(this.src_account,
|
var req = this.remote.request_path_find_create(
|
||||||
|
this.src_account,
|
||||||
this.dst_account,
|
this.dst_account,
|
||||||
this.dst_amount,
|
this.dst_amount,
|
||||||
this.src_currencies,
|
this.src_currencies);
|
||||||
handleInitialPath);
|
|
||||||
|
|
||||||
function handleInitialPath(err, msg) {
|
req.once('error', function(err) {
|
||||||
if (err) {
|
|
||||||
self.emit('error', err);
|
self.emit('error', err);
|
||||||
} else {
|
});
|
||||||
|
req.once('success', function(msg) {
|
||||||
self.notify_update(msg);
|
self.notify_update(msg);
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// XXX We should add ourselves to prepare_subscribe or a similar mechanism so
|
// XXX We should add ourselves to prepare_subscribe or a similar mechanism so
|
||||||
// that we can resubscribe after a reconnection.
|
// that we can resubscribe after a reconnection.
|
||||||
|
|
||||||
req.request();
|
req.broadcast().request();
|
||||||
};
|
};
|
||||||
|
|
||||||
PathFind.prototype.close = function () {
|
PathFind.prototype.close = function () {
|
||||||
this.remote.request_path_find_close().request();
|
this.remote.request_path_find_close().broadcast().request();
|
||||||
this.emit('end');
|
this.emit('end');
|
||||||
this.emit('close');
|
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;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
var async = require('async');
|
||||||
var UInt160 = require('./uint160').UInt160;
|
var UInt160 = require('./uint160').UInt160;
|
||||||
var Currency = require('./currency').Currency;
|
var Currency = require('./currency').Currency;
|
||||||
var RippleError = require('./rippleerror').RippleError;
|
var RippleError = require('./rippleerror').RippleError;
|
||||||
@@ -24,6 +25,9 @@ function Request(remote, command) {
|
|||||||
|
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
this.requested = false;
|
this.requested = false;
|
||||||
|
this.reconnectTimeout = 1000 * 3;
|
||||||
|
this.successEvent = 'success';
|
||||||
|
this.errorEvent = 'error';
|
||||||
this.message = {
|
this.message = {
|
||||||
command: command,
|
command: command,
|
||||||
id: void(0)
|
id: void(0)
|
||||||
@@ -32,22 +36,20 @@ function Request(remote, command) {
|
|||||||
|
|
||||||
util.inherits(Request, EventEmitter);
|
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.
|
// Send the request to a remote.
|
||||||
Request.prototype.request = function(servers, callback) {
|
Request.prototype.request = function(servers, callback) {
|
||||||
if (this.requested) {
|
this.emit('before');
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof servers === 'function') {
|
if (typeof servers === 'function') {
|
||||||
callback = servers;
|
callback = servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.callback(callback);
|
||||||
|
|
||||||
|
if (this.requested) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
this.requested = true;
|
this.requested = true;
|
||||||
this.on('error', function(){});
|
this.on('error', function(){});
|
||||||
this.emit('request', this.remote);
|
this.emit('request', this.remote);
|
||||||
@@ -61,7 +63,129 @@ Request.prototype.request = function(servers, callback) {
|
|||||||
this.remote.request(this);
|
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;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -73,6 +197,13 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof successEvent === 'string') {
|
||||||
|
this.successEvent = successEvent;
|
||||||
|
}
|
||||||
|
if (typeof errorEvent === 'string') {
|
||||||
|
this.errorEvent = errorEvent;
|
||||||
|
}
|
||||||
|
|
||||||
var called = false;
|
var called = false;
|
||||||
|
|
||||||
function requestSuccess(message) {
|
function requestSuccess(message) {
|
||||||
@@ -94,8 +225,8 @@ Request.prototype.callback = function(callback, successEvent, errorEvent) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.once(successEvent || 'success', requestSuccess);
|
this.once(this.successEvent, requestSuccess);
|
||||||
this.once(errorEvent || 'error' , requestError);
|
this.once(this.errorEvent, requestError);
|
||||||
this.request();
|
this.request();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -124,6 +255,7 @@ Request.prototype.timeout = function(duration, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit.call(self, 'timeout');
|
emit.call(self, 'timeout');
|
||||||
|
self.cancel();
|
||||||
}, duration);
|
}, duration);
|
||||||
|
|
||||||
this.emit = function() {
|
this.emit = function() {
|
||||||
@@ -157,9 +289,7 @@ Request.prototype.setServer = function(server) {
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (selected instanceof Server) {
|
|
||||||
this.server = selected;
|
this.server = selected;
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -222,11 +352,10 @@ Request.prototype.ledgerSelect = function(ledger) {
|
|||||||
case 'validated':
|
case 'validated':
|
||||||
this.message.ledger_index = ledger;
|
this.message.ledger_index = ledger;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (Number(ledger)) {
|
if (Number(ledger) && isFinite(Number(ledger))) {
|
||||||
this.message.ledger_index = 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;
|
this.message.ledger_hash = ledger;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -322,12 +451,8 @@ Request.prototype.addAccount = function(account, proposed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var processedAccount = UInt160.json_rewrite(account);
|
var processedAccount = UInt160.json_rewrite(account);
|
||||||
|
var prop = proposed === true ? 'accounts_proposed' : 'accounts';
|
||||||
if (proposed === true) {
|
this.message[prop] = (this.message[prop] || []).concat(processedAccount);
|
||||||
this.message.accounts_proposed = (this.message.accounts_proposed || []).concat(processedAccount);
|
|
||||||
} else {
|
|
||||||
this.message.accounts = (this.message.accounts || []).concat(processedAccount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
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;
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Seed support
|
// Seed support
|
||||||
//
|
//
|
||||||
@@ -6,16 +8,12 @@ var extend = require('extend');
|
|||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var sjcl = utils.sjcl;
|
var sjcl = utils.sjcl;
|
||||||
|
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
|
||||||
|
|
||||||
var Base = require('./base').Base;
|
var Base = require('./base').Base;
|
||||||
var UInt = require('./uint').UInt;
|
var UInt = require('./uint').UInt;
|
||||||
var UInt256 = require('./uint256').UInt256;
|
|
||||||
var UInt160 = require('./uint160').UInt160;
|
var UInt160 = require('./uint160').UInt160;
|
||||||
var KeyPair = require('./keypair').KeyPair;
|
var KeyPair = require('./keypair').KeyPair;
|
||||||
|
|
||||||
var Seed = extend(function() {
|
var Seed = extend(function() {
|
||||||
// Internal form: NaN or BigInteger
|
|
||||||
this._curve = sjcl.ecc.curves.k256;
|
this._curve = sjcl.ecc.curves.k256;
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
}, UInt);
|
}, UInt);
|
||||||
@@ -60,7 +58,7 @@ Seed.prototype.parse_passphrase = function (j) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Seed.prototype.to_json = function() {
|
Seed.prototype.to_json = function() {
|
||||||
if (!(this._value instanceof BigInteger)) {
|
if (!(this.is_valid())) {
|
||||||
return NaN;
|
return NaN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,20 +69,18 @@ Seed.prototype.to_json = function () {
|
|||||||
|
|
||||||
function append_int(a, i) {
|
function append_int(a, i) {
|
||||||
return [].concat(a, i >> 24, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
|
return [].concat(a, i >> 24, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
|
||||||
};
|
}
|
||||||
|
|
||||||
function firstHalfOfSHA512(bytes) {
|
function firstHalfOfSHA512(bytes) {
|
||||||
return sjcl.bitArray.bitSlice(
|
return sjcl.bitArray.bitSlice(
|
||||||
sjcl.hash.sha512.hash(sjcl.codec.bytes.toBits(bytes)),
|
sjcl.hash.sha512.hash(sjcl.codec.bytes.toBits(bytes)),
|
||||||
0, 256
|
0, 256
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
function SHA256_RIPEMD160(bits) {
|
// Removed a `*` so this JSDoc-ish syntax is ignored.
|
||||||
return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
|
// This will soon all change anyway.
|
||||||
};
|
/*
|
||||||
|
|
||||||
/**
|
|
||||||
* @param account
|
* @param account
|
||||||
* {undefined} take first, default, KeyPair
|
* {undefined} take first, default, KeyPair
|
||||||
*
|
*
|
||||||
@@ -95,8 +91,9 @@ function SHA256_RIPEMD160(bits) {
|
|||||||
* that is desired.
|
* that is desired.
|
||||||
*
|
*
|
||||||
* @param maxLoops (optional)
|
* @param maxLoops (optional)
|
||||||
* {Number} specifies the amount of attempts taken to generate
|
* {Number} specifies the amount of attempts taken
|
||||||
* a matching KeyPair
|
* to generate a matching KeyPair
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
Seed.prototype.get_key = function(account, maxLoops) {
|
Seed.prototype.get_key = function(account, maxLoops) {
|
||||||
var account_number = 0, address;
|
var account_number = 0, address;
|
||||||
@@ -119,7 +116,8 @@ Seed.prototype.get_key = function (account, maxLoops) {
|
|||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
private_gen = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(this.to_bytes(), i)));
|
private_gen = sjcl.bn.fromBits(
|
||||||
|
firstHalfOfSHA512(append_int(this.to_bytes(), i)));
|
||||||
i++;
|
i++;
|
||||||
} while (!curve.r.greaterEquals(private_gen));
|
} while (!curve.r.greaterEquals(private_gen));
|
||||||
|
|
||||||
@@ -133,7 +131,13 @@ Seed.prototype.get_key = function (account, maxLoops) {
|
|||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sec = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(append_int(public_gen.toBytesCompressed(), account_number), i)));
|
sec = sjcl.bn.fromBits(
|
||||||
|
firstHalfOfSHA512(
|
||||||
|
append_int(
|
||||||
|
append_int(public_gen.toBytesCompressed(), account_number)
|
||||||
|
,
|
||||||
|
i
|
||||||
|
)));
|
||||||
i++;
|
i++;
|
||||||
} while (!curve.r.greaterEquals(sec));
|
} while (!curve.r.greaterEquals(sec));
|
||||||
|
|
||||||
@@ -149,6 +153,7 @@ Seed.prototype.get_key = function (account, maxLoops) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} while (address && !key_pair.get_address().equals(address));
|
} while (address && !key_pair.get_address().equals(address));
|
||||||
|
|
||||||
return key_pair;
|
return key_pair;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
var binformat = require('./binformat');
|
var binformat = require('./binformat');
|
||||||
var stypes = require('./serializedtypes');
|
var stypes = require('./serializedtypes');
|
||||||
var UInt256 = require('./uint256').UInt256;
|
|
||||||
var Crypt = require('./crypt').Crypt;
|
var Crypt = require('./crypt').Crypt;
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
|
|
||||||
var sjcl = utils.sjcl;
|
var sjcl = utils.sjcl;
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
|
||||||
|
|
||||||
var TRANSACTION_TYPES = { };
|
var TRANSACTION_TYPES = { };
|
||||||
|
|
||||||
@@ -27,6 +28,15 @@ Object.keys(binformat.ter).forEach(function(key) {
|
|||||||
TRANSACTION_RESULTS[binformat.ter[key]] = key;
|
TRANSACTION_RESULTS[binformat.ter[key]] = key;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function normalize_sjcl_bn_hex(string) {
|
||||||
|
var hex = string.slice(2); // remove '0x' prefix
|
||||||
|
// now strip leading zeros
|
||||||
|
var i = _.findIndex(hex, function(c) {
|
||||||
|
return c !== '0';
|
||||||
|
});
|
||||||
|
return i >= 0 ? hex.slice(i) : '0';
|
||||||
|
}
|
||||||
|
|
||||||
function SerializedObject(buf) {
|
function SerializedObject(buf) {
|
||||||
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf))) {
|
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf))) {
|
||||||
this.buffer = buf;
|
this.buffer = buf;
|
||||||
@@ -38,11 +48,11 @@ function SerializedObject(buf) {
|
|||||||
throw new Error('Invalid buffer passed.');
|
throw new Error('Invalid buffer passed.');
|
||||||
}
|
}
|
||||||
this.pointer = 0;
|
this.pointer = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
SerializedObject.from_json = function(obj) {
|
SerializedObject.from_json = function(obj) {
|
||||||
// Create a copy of the object so we don't modify it
|
// Create a copy of the object so we don't modify it
|
||||||
var obj = extend(true, {}, obj);
|
obj = extend(true, {}, obj);
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
var typedef;
|
var typedef;
|
||||||
|
|
||||||
@@ -101,25 +111,25 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
|
|||||||
var field = spec[0];
|
var field = spec[0];
|
||||||
var requirement = spec[1];
|
var requirement = spec[1];
|
||||||
|
|
||||||
if (binformat.REQUIRED === requirement && obj[field] === void(0)) {
|
if (binformat.REQUIRED === requirement && obj[field] === undefined) {
|
||||||
missing_fields.push(field);
|
missing_fields.push(field);
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
if (missing_fields.length > 0) {
|
if (missing_fields.length > 0) {
|
||||||
var object_name;
|
var object_name;
|
||||||
|
|
||||||
if (obj.TransactionType !== void(0)) {
|
if (obj.TransactionType !== undefined) {
|
||||||
object_name = SerializedObject.lookup_type_tx(obj.TransactionType);
|
object_name = SerializedObject.lookup_type_tx(obj.TransactionType);
|
||||||
} else if (obj.LedgerEntryType != null){
|
} else if (obj.LedgerEntryType !== undefined) {
|
||||||
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
|
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
|
||||||
} else {
|
} else {
|
||||||
object_name = "TransactionMetaData";
|
object_name = 'TransactionMetaData';
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(object_name + " is missing fields: " +
|
throw new Error(object_name + ' is missing fields: ' +
|
||||||
JSON.stringify(missing_fields));
|
JSON.stringify(missing_fields));
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SerializedObject.prototype.append = function(bytes) {
|
SerializedObject.prototype.append = function(bytes) {
|
||||||
@@ -127,7 +137,17 @@ SerializedObject.prototype.append = function(bytes) {
|
|||||||
bytes = bytes.buffer;
|
bytes = bytes.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure both buffer and bytes are Array. Either could potentially be a
|
||||||
|
// Buffer.
|
||||||
|
if (Array.isArray(this.buffer) && Array.isArray(bytes)) {
|
||||||
|
// Array::concat is horribly slow where buffer length is 100 kbytes + One
|
||||||
|
// transaction with 1100 affected nodes took around 23 seconds to convert
|
||||||
|
// from json to bytes.
|
||||||
|
Array.prototype.push.apply(this.buffer, bytes);
|
||||||
|
} else {
|
||||||
this.buffer = this.buffer.concat(bytes);
|
this.buffer = this.buffer.concat(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
this.pointer += bytes.length;
|
this.pointer += bytes.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -152,7 +172,7 @@ function readOrPeek(advance) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
SerializedObject.prototype.read = readOrPeek(true);
|
SerializedObject.prototype.read = readOrPeek(true);
|
||||||
|
|
||||||
@@ -209,8 +229,11 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
|
|||||||
|
|
||||||
if (typeof structure.to_json === 'function') {
|
if (typeof structure.to_json === 'function') {
|
||||||
output = structure.to_json();
|
output = structure.to_json();
|
||||||
} else if (structure instanceof BigInteger) {
|
} else if (structure instanceof sjcl.bn) {
|
||||||
output = structure.toString(16).toUpperCase();
|
output = ('0000000000000000' +
|
||||||
|
normalize_sjcl_bn_hex(structure.toString())
|
||||||
|
.toUpperCase()
|
||||||
|
).slice(-16);
|
||||||
} else {
|
} else {
|
||||||
// new Array or Object
|
// new Array or Object
|
||||||
output = new structure.constructor();
|
output = new structure.constructor();
|
||||||
@@ -250,7 +273,7 @@ SerializedObject.prototype.hash = function(prefix) {
|
|||||||
var sign_buffer = new SerializedObject();
|
var sign_buffer = new SerializedObject();
|
||||||
|
|
||||||
// Add hashing prefix
|
// Add hashing prefix
|
||||||
if ("undefined" !== typeof prefix) {
|
if (typeof prefix !== 'undefined') {
|
||||||
stypes.Int32.serialize(sign_buffer, prefix);
|
stypes.Int32.serialize(sign_buffer, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,15 +291,9 @@ SerializedObject.prototype.signing_hash = SerializedObject.prototype.hash;
|
|||||||
SerializedObject.prototype.serialize_field = function(spec, obj) {
|
SerializedObject.prototype.serialize_field = function(spec, obj) {
|
||||||
var name = spec[0];
|
var name = spec[0];
|
||||||
var presence = spec[1];
|
var presence = spec[1];
|
||||||
var field_id = spec[2];
|
|
||||||
var Type = stypes[spec[3]];
|
|
||||||
|
|
||||||
if (typeof obj[name] !== 'undefined') {
|
if (typeof obj[name] !== 'undefined') {
|
||||||
// ST: Old serialization code
|
|
||||||
//this.append(SerializedObject.get_field_header(Type.id, field_id));
|
|
||||||
try {
|
try {
|
||||||
// ST: Old serialization code
|
|
||||||
//Type.serialize(this, obj[name]);
|
|
||||||
stypes.serialize(this, name, obj[name]);
|
stypes.serialize(this, name, obj[name]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Add field name to message and rethrow
|
// Add field name to message and rethrow
|
||||||
@@ -312,7 +329,7 @@ SerializedObject.sort_typedef = function(typedef) {
|
|||||||
function sort_field_compare(a, b) {
|
function sort_field_compare(a, b) {
|
||||||
// Sort by type id first, then by field id
|
// Sort by type id first, then by field id
|
||||||
return a[3] !== b[3] ? stypes[a[3]].id - stypes[b[3]].id : a[2] - b[2];
|
return a[3] !== b[3] ? stypes[a[3]].id - stypes[b[3]].id : a[2] - b[2];
|
||||||
};
|
}
|
||||||
|
|
||||||
return typedef.sort(sort_field_compare);
|
return typedef.sort(sort_field_compare);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type definitions for binary format.
|
* Type definitions for binary format.
|
||||||
*
|
*
|
||||||
@@ -8,72 +10,84 @@
|
|||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
|
var GlobalBigNumber = require('bignumber.js');
|
||||||
|
var Amount = require('./amount').Amount;
|
||||||
|
var Currency = require('./currency').Currency;
|
||||||
var binformat = require('./binformat');
|
var binformat = require('./binformat');
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var sjcl = utils.sjcl;
|
var sjcl = utils.sjcl;
|
||||||
|
var SJCL_BN = sjcl.bn;
|
||||||
|
|
||||||
var UInt128 = require('./uint128').UInt128;
|
var UInt128 = require('./uint128').UInt128;
|
||||||
var UInt160 = require('./uint160').UInt160;
|
var UInt160 = require('./uint160').UInt160;
|
||||||
var UInt256 = require('./uint256').UInt256;
|
var UInt256 = require('./uint256').UInt256;
|
||||||
var Base = require('./base').Base;
|
var Base = require('./base').Base;
|
||||||
|
|
||||||
var amount = require('./amount');
|
var BigNumber = GlobalBigNumber.another({
|
||||||
var Amount = amount.Amount;
|
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
|
||||||
var Currency = amount.Currency;
|
DECIMAL_PLACES: 40
|
||||||
|
});
|
||||||
|
|
||||||
// Shortcuts
|
function SerializedType(methods) {
|
||||||
var hex = sjcl.codec.hex;
|
|
||||||
var bytes = sjcl.codec.bytes;
|
|
||||||
var utf8 = sjcl.codec.utf8String;
|
|
||||||
|
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
|
||||||
|
|
||||||
|
|
||||||
var SerializedType = function (methods) {
|
|
||||||
extend(this, methods);
|
extend(this, methods);
|
||||||
};
|
}
|
||||||
|
|
||||||
function isNumber(val) {
|
function isNumber(val) {
|
||||||
return typeof val === 'number' && isFinite(val);
|
return typeof val === 'number' && isFinite(val);
|
||||||
};
|
}
|
||||||
|
|
||||||
function isString(val) {
|
function isString(val) {
|
||||||
return typeof val === 'string';
|
return typeof val === 'string';
|
||||||
};
|
}
|
||||||
|
|
||||||
function isHexInt64String(val) {
|
function isHexInt64String(val) {
|
||||||
return isString(val) && /^[0-9A-F]{0,16}$/i.test(val);
|
return isString(val) && /^[0-9A-F]{0,16}$/i.test(val);
|
||||||
};
|
}
|
||||||
|
|
||||||
function isCurrencyString(val) {
|
function serializeBits(so, bits, noLength) {
|
||||||
return isString(val) && /^[A-Z0-9]{3}$/.test(val);
|
var byteData = sjcl.codec.bytes.fromBits(bits);
|
||||||
};
|
|
||||||
|
|
||||||
function isBigInteger(val) {
|
|
||||||
return val instanceof BigInteger;
|
|
||||||
};
|
|
||||||
|
|
||||||
function serializeHex(so, hexData, noLength) {
|
|
||||||
var byteData = bytes.fromBits(hex.toBits(hexData));
|
|
||||||
if (!noLength) {
|
if (!noLength) {
|
||||||
SerializedType.serialize_varint(so, byteData.length);
|
SerializedType.serialize_varint(so, byteData.length);
|
||||||
}
|
}
|
||||||
so.append(byteData);
|
so.append(byteData);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function serializeHex(so, hexData, noLength) {
|
||||||
|
serializeBits(so, sjcl.codec.hex.toBits(hexData), noLength);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parses bytes as hex
|
* parses bytes as hex
|
||||||
|
*
|
||||||
|
* @param {Array} byte_array bytes
|
||||||
|
* @return {String} hex string
|
||||||
*/
|
*/
|
||||||
function convertByteArrayToHex(byte_array) {
|
function convertByteArrayToHex(byte_array) {
|
||||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
|
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array))
|
||||||
};
|
.toUpperCase();
|
||||||
|
|
||||||
function convertStringToHex(string) {
|
|
||||||
return hex.fromBits(utf8.toBits(string)).toUpperCase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertHexToString(hexString) {
|
function convertHexToString(hexString) {
|
||||||
return utf8.fromBits(hex.toBits(hexString));
|
var bits = sjcl.codec.hex.toBits(hexString);
|
||||||
|
return sjcl.codec.utf8String.fromBits(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort_fields(keys) {
|
||||||
|
function sort_field_compare(a, b) {
|
||||||
|
var a_field_coordinates = binformat.fieldsInverseMap[a];
|
||||||
|
var a_type_bits = a_field_coordinates[0];
|
||||||
|
var a_field_bits = a_field_coordinates[1];
|
||||||
|
var b_field_coordinates = binformat.fieldsInverseMap[b];
|
||||||
|
var b_type_bits = b_field_coordinates[0];
|
||||||
|
var b_field_bits = b_field_coordinates[1];
|
||||||
|
|
||||||
|
// Sort by type id first, then by field id
|
||||||
|
return a_type_bits !== b_type_bits
|
||||||
|
? a_type_bits - b_type_bits
|
||||||
|
: a_field_bits - b_field_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys.sort(sort_field_compare);
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializedType.serialize_varint = function (so, val) {
|
SerializedType.serialize_varint = function (so, val) {
|
||||||
@@ -116,13 +130,18 @@ SerializedType.prototype.parse_varint = function (so) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
// In the following, we assume that the inputs are in the proper range. Is this correct?
|
// In the following, we assume that the inputs are in the proper range. Is this
|
||||||
|
// correct?
|
||||||
// Helper functions for 1-, 2-, and 4-byte integers.
|
// Helper functions for 1-, 2-, and 4-byte integers.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an integer value into an array of bytes.
|
* Convert an integer value into an array of bytes.
|
||||||
*
|
*
|
||||||
* The result is appended to the serialized object ('so').
|
* The result is appended to the serialized object ('so').
|
||||||
|
*
|
||||||
|
* @param {Number} val value
|
||||||
|
* @param {Number} bytes byte size
|
||||||
|
* @return {Array} byte array
|
||||||
*/
|
*/
|
||||||
function convertIntegerToByteArray(val, bytes) {
|
function convertIntegerToByteArray(val, bytes) {
|
||||||
if (!isNumber(val)) {
|
if (!isNumber(val)) {
|
||||||
@@ -140,9 +159,10 @@ function convertIntegerToByteArray(val, bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return newBytes;
|
return newBytes;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Convert a certain number of bytes from the serialized object ('so') into an integer.
|
// Convert a certain number of bytes from the serialized object ('so') into an
|
||||||
|
// integer.
|
||||||
function readAndSum(so, bytes) {
|
function readAndSum(so, bytes) {
|
||||||
var sum = 0;
|
var sum = 0;
|
||||||
|
|
||||||
@@ -157,7 +177,7 @@ function readAndSum(so, bytes) {
|
|||||||
|
|
||||||
// Convert to unsigned integer
|
// Convert to unsigned integer
|
||||||
return sum >>> 0;
|
return sum >>> 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
var STInt8 = exports.Int8 = new SerializedType({
|
var STInt8 = exports.Int8 = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
@@ -170,6 +190,89 @@ var STInt8 = exports.Int8 = new SerializedType({
|
|||||||
|
|
||||||
STInt8.id = 16;
|
STInt8.id = 16;
|
||||||
|
|
||||||
|
function serialize(so, field_name, value) {
|
||||||
|
// so: a byte-stream to serialize into.
|
||||||
|
// field_name: a string for the field name ('LedgerEntryType' etc.)
|
||||||
|
// value: the value of that field.
|
||||||
|
var field_coordinates = binformat.fieldsInverseMap[field_name];
|
||||||
|
var type_bits = field_coordinates[0];
|
||||||
|
var field_bits = field_coordinates[1];
|
||||||
|
var tag_byte = (type_bits < 16
|
||||||
|
? type_bits << 4
|
||||||
|
: 0) | (field_bits < 16
|
||||||
|
? field_bits
|
||||||
|
: 0);
|
||||||
|
|
||||||
|
if (field_name === 'LedgerEntryType' && typeof value === 'string') {
|
||||||
|
value = binformat.ledger[value][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_name === 'TransactionResult' && typeof value === 'string') {
|
||||||
|
value = binformat.ter[value];
|
||||||
|
}
|
||||||
|
|
||||||
|
STInt8.serialize(so, tag_byte);
|
||||||
|
|
||||||
|
if (type_bits >= 16) {
|
||||||
|
STInt8.serialize(so, type_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_bits >= 16) {
|
||||||
|
STInt8.serialize(so, field_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the serializer class (ST...)
|
||||||
|
var serialized_object_type;
|
||||||
|
|
||||||
|
if (field_name === 'Memo' && typeof value === 'object') {
|
||||||
|
// for Memo we override the default behavior with our STMemo serializer
|
||||||
|
serialized_object_type = exports.STMemo;
|
||||||
|
} else {
|
||||||
|
// for a field based on the type bits.
|
||||||
|
serialized_object_type = exports[binformat.types[type_bits]];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
serialized_object_type.serialize(so, value);
|
||||||
|
} catch (e) {
|
||||||
|
e.message += ' (' + field_name + ')';
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.serialize = exports.serialize_whatever = serialize;
|
||||||
|
|
||||||
|
// Take the serialized object, figure out what type/field it is, and return the
|
||||||
|
// parsing of that.
|
||||||
|
|
||||||
|
function parse(so) {
|
||||||
|
var tag_byte = so.read(1)[0];
|
||||||
|
var type_bits = tag_byte >> 4;
|
||||||
|
|
||||||
|
if (type_bits === 0) {
|
||||||
|
type_bits = so.read(1)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var field_bits = tag_byte & 0x0f;
|
||||||
|
var field_name = (field_bits === 0)
|
||||||
|
? field_name = binformat.fields[type_bits][so.read(1)[0]]
|
||||||
|
: field_name = binformat.fields[type_bits][field_bits];
|
||||||
|
|
||||||
|
assert(field_name, 'Unknown field - header byte is 0x'
|
||||||
|
+ tag_byte.toString(16));
|
||||||
|
|
||||||
|
// Get the parser class (ST...) for a field based on the type bits.
|
||||||
|
var type = (field_name === 'Memo')
|
||||||
|
? exports.STMemo
|
||||||
|
: exports[binformat.types[type_bits]];
|
||||||
|
|
||||||
|
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
||||||
|
|
||||||
|
return [field_name, type.parse(so)]; // key, value
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.parse = exports.parse_whatever = parse;
|
||||||
|
|
||||||
var STInt16 = exports.Int16 = new SerializedType({
|
var STInt16 = exports.Int16 = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
so.append(convertIntegerToByteArray(val, 2));
|
so.append(convertIntegerToByteArray(val, 2));
|
||||||
@@ -201,40 +304,25 @@ var STInt64 = exports.Int64 = new SerializedType({
|
|||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
throw new Error('Negative value for unsigned Int64 is invalid.');
|
||||||
}
|
}
|
||||||
bigNumObject = new BigInteger(String(val), 10);
|
bigNumObject = new SJCL_BN(val, 10);
|
||||||
} else if (isString(val)) {
|
} else if (isString(val)) {
|
||||||
if (!isHexInt64String(val)) {
|
if (!isHexInt64String(val)) {
|
||||||
throw new Error('Not a valid hex Int64.');
|
throw new Error('Not a valid hex Int64.');
|
||||||
}
|
}
|
||||||
bigNumObject = new BigInteger(val, 16);
|
bigNumObject = new SJCL_BN(val, 16);
|
||||||
} else if (isBigInteger(val)) {
|
} else if (val instanceof SJCL_BN) {
|
||||||
if (val.compareTo(BigInteger.ZERO) < 0) {
|
if (!val.greaterEquals(0)) {
|
||||||
throw new Error('Negative value for unsigned Int64 is invalid.');
|
throw new Error('Negative value for unsigned Int64 is invalid.');
|
||||||
}
|
}
|
||||||
bigNumObject = val;
|
bigNumObject = val;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid type for Int64');
|
throw new Error('Invalid type for Int64');
|
||||||
}
|
}
|
||||||
|
serializeBits(so, bigNumObject.toBits(64), true); // noLength = true
|
||||||
var hex = bigNumObject.toString(16);
|
|
||||||
|
|
||||||
if (hex.length > 16) {
|
|
||||||
throw new Error('Int64 is too large');
|
|
||||||
}
|
|
||||||
|
|
||||||
while (hex.length < 16) {
|
|
||||||
hex = '0' + hex;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializeHex(so, hex, true); //noLength = true
|
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
var bytes = so.read(8);
|
var bytes = so.read(8);
|
||||||
// We need to add a 0, so if the high bit is set it won't think it's a
|
return SJCL_BN.fromBits(sjcl.codec.bytes.toBits(bytes));
|
||||||
// pessimistic numeric fraek. What doth lief?
|
|
||||||
var result = new BigInteger([0].concat(bytes), 256);
|
|
||||||
assert(result instanceof BigInteger);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -246,7 +334,7 @@ var STHash128 = exports.Hash128 = new SerializedType({
|
|||||||
if (!hash.is_valid()) {
|
if (!hash.is_valid()) {
|
||||||
throw new Error('Invalid Hash128');
|
throw new Error('Invalid Hash128');
|
||||||
}
|
}
|
||||||
serializeHex(so, hash.to_hex(), true); //noLength = true
|
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return UInt128.from_bytes(so.read(16));
|
return UInt128.from_bytes(so.read(16));
|
||||||
@@ -261,7 +349,7 @@ var STHash256 = exports.Hash256 = new SerializedType({
|
|||||||
if (!hash.is_valid()) {
|
if (!hash.is_valid()) {
|
||||||
throw new Error('Invalid Hash256');
|
throw new Error('Invalid Hash256');
|
||||||
}
|
}
|
||||||
serializeHex(so, hash.to_hex(), true); //noLength = true
|
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return UInt256.from_bytes(so.read(32));
|
return UInt256.from_bytes(so.read(32));
|
||||||
@@ -276,7 +364,7 @@ var STHash160 = exports.Hash160 = new SerializedType({
|
|||||||
if (!hash.is_valid()) {
|
if (!hash.is_valid()) {
|
||||||
throw new Error('Invalid Hash160');
|
throw new Error('Invalid Hash160');
|
||||||
}
|
}
|
||||||
serializeHex(so, hash.to_hex(), true); //noLength = true
|
serializeBits(so, hash.to_bits(), true); // noLength = true
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
return UInt160.from_bytes(so.read(20));
|
return UInt160.from_bytes(so.read(20));
|
||||||
@@ -287,11 +375,12 @@ STHash160.id = 17;
|
|||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
var STCurrency = new SerializedType({
|
var STCurrency = new SerializedType({
|
||||||
serialize: function (so, val, xrp_as_ascii) {
|
serialize: function (so, val) {
|
||||||
var currencyData = val.to_bytes();
|
var currencyData = val.to_bytes();
|
||||||
|
|
||||||
if (!currencyData) {
|
if (!currencyData) {
|
||||||
throw new Error('Tried to serialize invalid/unimplemented currency type.');
|
throw new Error(
|
||||||
|
'Tried to serialize invalid/unimplemented currency type.');
|
||||||
}
|
}
|
||||||
|
|
||||||
so.append(currencyData);
|
so.append(currencyData);
|
||||||
@@ -301,7 +390,8 @@ var STCurrency = new SerializedType({
|
|||||||
var currency = Currency.from_bytes(bytes);
|
var currency = Currency.from_bytes(bytes);
|
||||||
// XXX Disabled check. Theoretically, the Currency class should support any
|
// XXX Disabled check. Theoretically, the Currency class should support any
|
||||||
// UInt160 value and consider it valid. But it doesn't, so for the
|
// UInt160 value and consider it valid. But it doesn't, so for the
|
||||||
// deserialization to be usable, we need to allow invalid results for now.
|
// deserialization to be usable, we need to allow invalid results for
|
||||||
|
// now.
|
||||||
// if (!currency.is_valid()) {
|
// if (!currency.is_valid()) {
|
||||||
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
|
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
|
||||||
// }
|
// }
|
||||||
@@ -312,18 +402,26 @@ var STCurrency = new SerializedType({
|
|||||||
var STAmount = exports.Amount = new SerializedType({
|
var STAmount = exports.Amount = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
var amount = Amount.from_json(val);
|
var amount = Amount.from_json(val);
|
||||||
|
|
||||||
if (!amount.is_valid()) {
|
if (!amount.is_valid()) {
|
||||||
throw new Error('Not a valid Amount object.');
|
throw new Error('Not a valid Amount object.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var value = new BigNumber(amount.to_text());
|
||||||
|
var offset = value.e - 15;
|
||||||
|
|
||||||
// Amount (64-bit integer)
|
// Amount (64-bit integer)
|
||||||
var valueBytes = utils.arraySet(8, 0);
|
var valueBytes = utils.arraySet(8, 0);
|
||||||
|
|
||||||
if (amount.is_native()) {
|
if (amount.is_native()) {
|
||||||
var valueHex = amount._value.toString(16);
|
var valueHex = value.abs().toString(16);
|
||||||
|
|
||||||
|
if (Amount.strict_mode && value.abs().greaterThan(Amount.bi_xns_max)) {
|
||||||
|
throw new Error('Value out of bounds');
|
||||||
|
}
|
||||||
|
|
||||||
// Enforce correct length (64 bits)
|
// Enforce correct length (64 bits)
|
||||||
if (valueHex.length > 16) {
|
if (Amount.strict_mode && valueHex.length > 16) {
|
||||||
throw new Error('Value out of bounds');
|
throw new Error('Value out of bounds');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +429,7 @@ var STAmount = exports.Amount = new SerializedType({
|
|||||||
valueHex = '0' + valueHex;
|
valueHex = '0' + valueHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
valueBytes = bytes.fromBits(hex.toBits(valueHex));
|
valueBytes = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(valueHex));
|
||||||
// Clear most significant two bits - these bits should already be 0 if
|
// Clear most significant two bits - these bits should already be 0 if
|
||||||
// Amount enforces the range correctly, but we'll clear them anyway just
|
// Amount enforces the range correctly, but we'll clear them anyway just
|
||||||
// so this code can make certain guarantees about the encoded value.
|
// so this code can make certain guarantees about the encoded value.
|
||||||
@@ -353,10 +451,16 @@ var STAmount = exports.Amount = new SerializedType({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Next eight bits: offset/exponent
|
// Next eight bits: offset/exponent
|
||||||
hi |= ((97 + amount._offset) & 0xff) << 22;
|
hi |= ((97 + offset) & 0xff) << 22;
|
||||||
|
|
||||||
// Remaining 54 bits: mantissa
|
// Remaining 54 bits: mantissa
|
||||||
hi |= amount._value.shiftRight(32).intValue() & 0x3fffff;
|
var mantissaDecimal = utils.getMantissaDecimalString(value.abs());
|
||||||
lo = amount._value.intValue() & 0xffffffff;
|
var mantissaHex = (new BigNumber(mantissaDecimal)).toString(16);
|
||||||
|
assert(mantissaHex.length <= 16,
|
||||||
|
'Mantissa hex representation ' + mantissaHex +
|
||||||
|
' exceeds the maximum length of 16');
|
||||||
|
hi |= parseInt(mantissaHex.slice(0, -8), 16) & 0x3fffff;
|
||||||
|
lo = parseInt(mantissaHex.slice(-8), 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
valueBytes = sjcl.codec.bytes.fromBits([hi, lo]);
|
valueBytes = sjcl.codec.bytes.fromBits([hi, lo]);
|
||||||
@@ -374,7 +478,6 @@ var STAmount = exports.Amount = new SerializedType({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
var amount = new Amount();
|
|
||||||
var value_bytes = so.read(8);
|
var value_bytes = so.read(8);
|
||||||
var is_zero = !(value_bytes[0] & 0x7f);
|
var is_zero = !(value_bytes[0] & 0x7f);
|
||||||
|
|
||||||
@@ -382,6 +485,8 @@ var STAmount = exports.Amount = new SerializedType({
|
|||||||
is_zero = is_zero && !value_bytes[i];
|
is_zero = is_zero && !value_bytes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var is_negative = !is_zero && !(value_bytes[0] & 0x40);
|
||||||
|
|
||||||
if (value_bytes[0] & 0x80) {
|
if (value_bytes[0] & 0x80) {
|
||||||
// non-native
|
// non-native
|
||||||
var currency = STCurrency.parse(so);
|
var currency = STCurrency.parse(so);
|
||||||
@@ -391,26 +496,23 @@ var STAmount = exports.Amount = new SerializedType({
|
|||||||
var offset = ((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
|
var offset = ((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
|
||||||
var mantissa_bytes = value_bytes.slice(1);
|
var mantissa_bytes = value_bytes.slice(1);
|
||||||
mantissa_bytes[0] &= 0x3f;
|
mantissa_bytes[0] &= 0x3f;
|
||||||
var value = new BigInteger(mantissa_bytes, 256);
|
var mantissa = new BigNumber(utils.arrayToHex(mantissa_bytes), 16);
|
||||||
|
var sign = is_negative ? '-' : '';
|
||||||
|
var valueString = sign + mantissa.toString() + 'e' + offset.toString();
|
||||||
|
|
||||||
if (value.equals(BigInteger.ZERO) && !is_zero ) {
|
return Amount.from_json({
|
||||||
throw new Error('Invalid zero representation');
|
currency: currency,
|
||||||
|
issuer: issuer.to_json(),
|
||||||
|
value: valueString
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
amount._value = value;
|
|
||||||
amount._offset = offset;
|
|
||||||
amount._currency = currency;
|
|
||||||
amount._issuer = issuer;
|
|
||||||
amount._is_native = false;
|
|
||||||
} else {
|
|
||||||
// native
|
// native
|
||||||
var integer_bytes = value_bytes.slice();
|
var integer_bytes = value_bytes.slice();
|
||||||
integer_bytes[0] &= 0x3f;
|
integer_bytes[0] &= 0x3f;
|
||||||
amount._value = new BigInteger(integer_bytes, 256);
|
var integer_hex = utils.arrayToHex(integer_bytes);
|
||||||
amount._is_native = true;
|
var value = new BigNumber(integer_hex, 16);
|
||||||
}
|
return Amount.from_json((is_negative ? '-' : '') + value.toString());
|
||||||
amount._is_negative = !is_zero && !(value_bytes[0] & 0x40);
|
|
||||||
return amount;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -418,7 +520,6 @@ STAmount.id = 6;
|
|||||||
|
|
||||||
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
var STVL = exports.VariableLength = exports.VL = new SerializedType({
|
||||||
serialize: function (so, val) {
|
serialize: function (so, val) {
|
||||||
|
|
||||||
if (typeof val === 'string') {
|
if (typeof val === 'string') {
|
||||||
serializeHex(so, val);
|
serializeHex(so, val);
|
||||||
} else {
|
} else {
|
||||||
@@ -439,7 +540,7 @@ var STAccount = exports.Account = new SerializedType({
|
|||||||
if (!account.is_valid()) {
|
if (!account.is_valid()) {
|
||||||
throw new Error('Invalid account!');
|
throw new Error('Invalid account!');
|
||||||
}
|
}
|
||||||
serializeHex(so, account.to_hex());
|
serializeBits(so, account.to_bits());
|
||||||
},
|
},
|
||||||
parse: function (so) {
|
parse: function (so) {
|
||||||
var len = this.parse_varint(so);
|
var len = this.parse_varint(so);
|
||||||
@@ -492,7 +593,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
|||||||
STInt8.serialize(so, type);
|
STInt8.serialize(so, type);
|
||||||
|
|
||||||
if (entry.account) {
|
if (entry.account) {
|
||||||
so.append(UInt160.from_json(entry.account).to_bytes());
|
STHash160.serialize(so, entry.account);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.currency) {
|
if (entry.currency) {
|
||||||
@@ -501,7 +602,7 @@ var STPathSet = exports.PathSet = new SerializedType({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (entry.issuer) {
|
if (entry.issuer) {
|
||||||
so.append(UInt160.from_json(entry.issuer).to_bytes());
|
STHash160.serialize(so, entry.issuer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,19 +619,22 @@ var STPathSet = exports.PathSet = new SerializedType({
|
|||||||
[]
|
[]
|
||||||
]
|
]
|
||||||
|
|
||||||
each entry has one or more of the following attributes: amount, currency, issuer.
|
each entry has one or more of the following attributes:
|
||||||
|
amount, currency, issuer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var path_list = [];
|
var path_list = [];
|
||||||
var current_path = [];
|
var current_path = [];
|
||||||
var tag_byte;
|
var tag_byte;
|
||||||
|
|
||||||
|
/* eslint-disable no-cond-assign */
|
||||||
|
|
||||||
while ((tag_byte = so.read(1)[0]) !== this.typeEnd) {
|
while ((tag_byte = so.read(1)[0]) !== this.typeEnd) {
|
||||||
//TODO: try/catch this loop, and catch when we run out of data without reaching the end of the data structure.
|
// TODO: try/catch this loop, and catch when we run out of data without
|
||||||
|
// reaching the end of the data structure.
|
||||||
// Now determine: is this an end, boundary, or entry-begin-tag?
|
// Now determine: is this an end, boundary, or entry-begin-tag?
|
||||||
// console.log('Tag byte:', tag_byte);
|
// console.log('Tag byte:', tag_byte);
|
||||||
if (tag_byte === this.typeBoundary) {
|
if (tag_byte === this.typeBoundary) {
|
||||||
//console.log('Boundary');
|
|
||||||
if (current_path) { // close the current path, if there is one,
|
if (current_path) { // close the current path, if there is one,
|
||||||
path_list.push(current_path);
|
path_list.push(current_path);
|
||||||
}
|
}
|
||||||
@@ -539,35 +643,35 @@ var STPathSet = exports.PathSet = new SerializedType({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// It's an entry-begin tag.
|
// It's an entry-begin tag.
|
||||||
//console.log('It's an entry-begin tag.');
|
|
||||||
var entry = {};
|
var entry = {};
|
||||||
|
var type = 0;
|
||||||
|
|
||||||
if (tag_byte & this.typeAccount) {
|
if (tag_byte & this.typeAccount) {
|
||||||
//console.log('entry.account');
|
|
||||||
/*var bta = so.read(20);
|
|
||||||
console.log('BTA:', bta);*/
|
|
||||||
entry.account = STHash160.parse(so);
|
entry.account = STHash160.parse(so);
|
||||||
entry.account.set_version(Base.VER_ACCOUNT_ID);
|
entry.account.set_version(Base.VER_ACCOUNT_ID);
|
||||||
|
type = type | this.typeAccount;
|
||||||
}
|
}
|
||||||
if (tag_byte & this.typeCurrency) {
|
if (tag_byte & this.typeCurrency) {
|
||||||
//console.log('entry.currency');
|
|
||||||
entry.currency = STCurrency.parse(so);
|
entry.currency = STCurrency.parse(so);
|
||||||
if (entry.currency.to_json() === 'XRP' && !entry.currency.is_native()) {
|
if (entry.currency.to_json() === 'XRP' && !entry.currency.is_native()) {
|
||||||
entry.non_native = true;
|
entry.non_native = true;
|
||||||
}
|
}
|
||||||
|
type = type | this.typeCurrency;
|
||||||
}
|
}
|
||||||
if (tag_byte & this.typeIssuer) {
|
if (tag_byte & this.typeIssuer) {
|
||||||
//console.log('entry.issuer');
|
|
||||||
entry.issuer = STHash160.parse(so);
|
entry.issuer = STHash160.parse(so);
|
||||||
// Enable and set correct type of base-58 encoding
|
// Enable and set correct type of base-58 encoding
|
||||||
entry.issuer.set_version(Base.VER_ACCOUNT_ID);
|
entry.issuer.set_version(Base.VER_ACCOUNT_ID);
|
||||||
//console.log('DONE WITH ISSUER!');
|
type = type | this.typeIssuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.account || entry.currency || entry.issuer) {
|
if (entry.account || entry.currency || entry.issuer) {
|
||||||
|
entry.type = type;
|
||||||
|
entry.type_hex = ('000000000000000' + type.toString(16)).slice(-16);
|
||||||
current_path.push(entry);
|
current_path.push(entry);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid path entry'); //It must have at least something in it.
|
// It must have at least something in it.
|
||||||
|
throw new Error('Invalid path entry');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,8 +687,9 @@ var STPathSet = exports.PathSet = new SerializedType({
|
|||||||
STPathSet.id = 18;
|
STPathSet.id = 18;
|
||||||
|
|
||||||
var STVector256 = exports.Vector256 = new SerializedType({
|
var STVector256 = exports.Vector256 = new SerializedType({
|
||||||
serialize: function (so, val) { //Assume val is an array of STHash256 objects.
|
serialize: function(so, val) {
|
||||||
var length_as_varint = SerializedType.serialize_varint(so, val.length * 32);
|
// Assume val is an array of STHash256 objects.
|
||||||
|
SerializedType.serialize_varint(so, val.length * 32);
|
||||||
for (var i = 0, l = val.length; i < l; i++) {
|
for (var i = 0, l = val.length; i < l; i++) {
|
||||||
STHash256.serialize(so, val[i]);
|
STHash256.serialize(so, val[i]);
|
||||||
}
|
}
|
||||||
@@ -603,9 +708,8 @@ var STVector256 = exports.Vector256 = new SerializedType({
|
|||||||
STVector256.id = 19;
|
STVector256.id = 19;
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
var STMemo = exports.STMemo = new SerializedType({
|
exports.STMemo = new SerializedType({
|
||||||
serialize: function(so, val, no_marker) {
|
serialize: function(so, val, no_marker) {
|
||||||
|
|
||||||
var keys = [];
|
var keys = [];
|
||||||
|
|
||||||
Object.keys(val).forEach(function (key) {
|
Object.keys(val).forEach(function (key) {
|
||||||
@@ -625,73 +729,64 @@ var STMemo = exports.STMemo = new SerializedType({
|
|||||||
// Sort fields
|
// Sort fields
|
||||||
keys = sort_fields(keys);
|
keys = sort_fields(keys);
|
||||||
|
|
||||||
// store that we're dealing with json
|
keys.forEach(function(key) {
|
||||||
var isJson = val.MemoFormat === 'json';
|
serialize(so, key, val[key]);
|
||||||
|
});
|
||||||
for (var i=0; i<keys.length; i++) {
|
|
||||||
var key = keys[i];
|
|
||||||
var value = val[key];
|
|
||||||
switch (key) {
|
|
||||||
|
|
||||||
// MemoType and MemoFormat are always ASCII strings
|
|
||||||
case 'MemoType':
|
|
||||||
case 'MemoFormat':
|
|
||||||
value = convertStringToHex(value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// MemoData can be a JSON object, otherwise it's a string
|
|
||||||
case 'MemoData':
|
|
||||||
if (typeof value !== 'string') {
|
|
||||||
if (isJson) {
|
|
||||||
try {
|
|
||||||
value = convertStringToHex(JSON.stringify(value));
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('MemoFormat json with invalid JSON in MemoData field');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error('MemoData can only be a JSON object with a valid json MemoFormat');
|
|
||||||
}
|
|
||||||
} else if (isString(value)) {
|
|
||||||
value = convertStringToHex(value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize(so, key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!no_marker) {
|
if (!no_marker) {
|
||||||
// Object ending marker
|
// Object ending marker
|
||||||
STInt8.serialize(so, 0xe1);
|
STInt8.serialize(so, 0xe1);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
parse: function(so) {
|
parse: function(so) {
|
||||||
var output = {};
|
var output = {};
|
||||||
|
|
||||||
while (so.peek(1)[0] !== 0xe1) {
|
while (so.peek(1)[0] !== 0xe1) {
|
||||||
var keyval = parse(so);
|
var keyval = parse(so);
|
||||||
output[keyval[0]] = keyval[1];
|
output[keyval[0]] = keyval[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output['MemoType'] !== void(0)) {
|
if (output.MemoType !== undefined) {
|
||||||
output['parsed_memo_type'] = convertHexToString(output['MemoType']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output['MemoFormat'] !== void(0)) {
|
|
||||||
output['parsed_memo_format'] = convertHexToString(output['MemoFormat']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output['MemoData'] !== void(0)) {
|
|
||||||
|
|
||||||
// see if we can parse JSON
|
|
||||||
if (output['parsed_memo_format'] === 'json') {
|
|
||||||
try {
|
try {
|
||||||
output['parsed_memo_data'] = JSON.parse(convertHexToString(output['MemoData']));
|
var parsedType = convertHexToString(output.MemoType);
|
||||||
} catch(e) {
|
|
||||||
// fail, which is fine, we just won't add the memo_data field
|
if (parsedType !== 'unformatted_memo') {
|
||||||
|
output.parsed_memo_type = parsedType;
|
||||||
}
|
}
|
||||||
} else if(output['parsed_memo_format'] === 'text') {
|
} catch (e) {
|
||||||
output['parsed_memo_data'] = convertHexToString(output['MemoData']);
|
// we don't know what's in the binary, apparently it's not a UTF-8
|
||||||
|
// string
|
||||||
|
// this is fine, we won't add the parsed_memo_type field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.MemoFormat !== undefined) {
|
||||||
|
try {
|
||||||
|
output.parsed_memo_format = convertHexToString(output.MemoFormat);
|
||||||
|
} catch (e) {
|
||||||
|
// we don't know what's in the binary, apparently it's not a UTF-8
|
||||||
|
// string
|
||||||
|
// this is fine, we won't add the parsed_memo_format field
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output.MemoData !== undefined) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (output.parsed_memo_format === 'json') {
|
||||||
|
// see if we can parse JSON
|
||||||
|
output.parsed_memo_data =
|
||||||
|
JSON.parse(convertHexToString(output.MemoData));
|
||||||
|
|
||||||
|
} else if (output.parsed_memo_format === 'text') {
|
||||||
|
// otherwise see if we can parse text
|
||||||
|
output.parsed_memo_data = convertHexToString(output.MemoData);
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
// we'll fail in case the content does not match what the MemoFormat
|
||||||
|
// described
|
||||||
|
// this is fine, we won't add the parsed_memo_data, the user has to
|
||||||
|
// parse themselves
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,98 +796,6 @@ var STMemo = exports.STMemo = new SerializedType({
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.serialize = exports.serialize_whatever = serialize;
|
|
||||||
|
|
||||||
function serialize(so, field_name, value) {
|
|
||||||
//so: a byte-stream to serialize into.
|
|
||||||
//field_name: a string for the field name ('LedgerEntryType' etc.)
|
|
||||||
//value: the value of that field.
|
|
||||||
var field_coordinates = binformat.fieldsInverseMap[field_name];
|
|
||||||
var type_bits = field_coordinates[0];
|
|
||||||
var field_bits = field_coordinates[1];
|
|
||||||
var tag_byte = (type_bits < 16 ? type_bits << 4 : 0) | (field_bits < 16 ? field_bits : 0);
|
|
||||||
|
|
||||||
if (field_name === 'LedgerEntryType' && 'string' === typeof value) {
|
|
||||||
value = binformat.ledger[value][0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field_name === 'TransactionResult' && 'string' === typeof value) {
|
|
||||||
value = binformat.ter[value];
|
|
||||||
}
|
|
||||||
|
|
||||||
STInt8.serialize(so, tag_byte);
|
|
||||||
|
|
||||||
if (type_bits >= 16) {
|
|
||||||
STInt8.serialize(so, type_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field_bits >= 16) {
|
|
||||||
STInt8.serialize(so, field_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the serializer class (ST...)
|
|
||||||
var serialized_object_type;
|
|
||||||
if (field_name === 'Memo' && typeof value === 'object') {
|
|
||||||
// for Memo we override the default behavior with our STMemo serializer
|
|
||||||
serialized_object_type = exports.STMemo;
|
|
||||||
} else {
|
|
||||||
// for a field based on the type bits.
|
|
||||||
serialized_object_type = exports[binformat.types[type_bits]];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
serialized_object_type.serialize(so, value);
|
|
||||||
} catch (e) {
|
|
||||||
e.message += ' (' + field_name + ')';
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Take the serialized object, figure out what type/field it is, and return the parsing of that.
|
|
||||||
exports.parse = exports.parse_whatever = parse;
|
|
||||||
|
|
||||||
function parse(so) {
|
|
||||||
var tag_byte = so.read(1)[0];
|
|
||||||
var type_bits = tag_byte >> 4;
|
|
||||||
|
|
||||||
if (type_bits === 0) {
|
|
||||||
type_bits = so.read(1)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var field_bits = tag_byte & 0x0f;
|
|
||||||
var field_name = (field_bits === 0)
|
|
||||||
? field_name = binformat.fields[type_bits][so.read(1)[0]]
|
|
||||||
: field_name = binformat.fields[type_bits][field_bits];
|
|
||||||
|
|
||||||
assert(field_name, 'Unknown field - header byte is 0x' + tag_byte.toString(16));
|
|
||||||
|
|
||||||
// Get the parser class (ST...) for a field based on the type bits.
|
|
||||||
var type = (field_name === 'Memo')
|
|
||||||
? exports.STMemo
|
|
||||||
: exports[binformat.types[type_bits]];
|
|
||||||
|
|
||||||
assert(type, 'Unknown type - header byte is 0x' + tag_byte.toString(16));
|
|
||||||
|
|
||||||
return [ field_name, type.parse(so) ]; //key, value
|
|
||||||
};
|
|
||||||
|
|
||||||
function sort_fields(keys) {
|
|
||||||
function sort_field_compare(a, b) {
|
|
||||||
var a_field_coordinates = binformat.fieldsInverseMap[a];
|
|
||||||
var a_type_bits = a_field_coordinates[0];
|
|
||||||
var a_field_bits = a_field_coordinates[1];
|
|
||||||
var b_field_coordinates = binformat.fieldsInverseMap[b];
|
|
||||||
var b_type_bits = b_field_coordinates[0];
|
|
||||||
var b_field_bits = b_field_coordinates[1];
|
|
||||||
|
|
||||||
// Sort by type id first, then by field id
|
|
||||||
return a_type_bits !== b_type_bits ? a_type_bits - b_type_bits : a_field_bits - b_field_bits;
|
|
||||||
};
|
|
||||||
|
|
||||||
return keys.sort(sort_field_compare);
|
|
||||||
}
|
|
||||||
|
|
||||||
var STObject = exports.Object = new SerializedType({
|
var STObject = exports.Object = new SerializedType({
|
||||||
serialize: function (so, val, no_marker) {
|
serialize: function (so, val, no_marker) {
|
||||||
var keys = [];
|
var keys = [];
|
||||||
@@ -843,7 +846,8 @@ var STArray = exports.Array = new SerializedType({
|
|||||||
var keys = Object.keys(val[i]);
|
var keys = Object.keys(val[i]);
|
||||||
|
|
||||||
if (keys.length !== 1) {
|
if (keys.length !== 1) {
|
||||||
throw Error('Cannot serialize an array containing non-single-key objects');
|
throw new Error(
|
||||||
|
'Cannot serialize an array containing non-single-key objects');
|
||||||
}
|
}
|
||||||
|
|
||||||
var field_name = keys[0];
|
var field_name = keys[0];
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
var util = require('util');
|
var util = require('util');
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
|
var LRU = require('lru-cache');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var Amount = require('./amount').Amount;
|
var Amount = require('./amount').Amount;
|
||||||
|
var RangeSet = require('./rangeset').RangeSet;
|
||||||
var log = require('./log').internal.sub('server');
|
var log = require('./log').internal.sub('server');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +34,7 @@ function Server(remote, opts) {
|
|||||||
throw new TypeError('Server configuration is not an Object');
|
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');
|
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._connected = false;
|
||||||
this._shouldConnect = false;
|
this._shouldConnect = false;
|
||||||
this._state = 'offline';
|
this._state = 'offline';
|
||||||
|
this._ledgerRanges = new RangeSet();
|
||||||
|
this._ledgerMap = LRU({ max: 200 });
|
||||||
|
|
||||||
this._id = 0; // request ID
|
this._id = 0; // request ID
|
||||||
this._retry = 0;
|
this._retry = 0;
|
||||||
@@ -117,31 +121,29 @@ function Server(remote, opts) {
|
|||||||
self._updateScore('loadchange', load);
|
self._updateScore('loadchange', load);
|
||||||
});
|
});
|
||||||
|
|
||||||
// If server is not up-to-date, request server_info
|
this.on('connect', function() {
|
||||||
// for getting pubkey_node & hostid information.
|
self.requestServerID();
|
||||||
// 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);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
util.inherits(Server, EventEmitter);
|
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.
|
* 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.
|
* Server maintains a score for request prioritization.
|
||||||
*
|
*
|
||||||
@@ -328,6 +355,8 @@ Server.prototype.disconnect = function() {
|
|||||||
this._lastLedgerClose = NaN;
|
this._lastLedgerClose = NaN;
|
||||||
this._score = 0;
|
this._score = 0;
|
||||||
this._shouldConnect = false;
|
this._shouldConnect = false;
|
||||||
|
this._ledgerRanges.reset();
|
||||||
|
this._ledgerMap.reset();
|
||||||
this._setState('offline');
|
this._setState('offline');
|
||||||
|
|
||||||
if (this._ws) {
|
if (this._ws) {
|
||||||
@@ -420,6 +449,11 @@ Server.prototype.connect = function() {
|
|||||||
log.info(self.getServerID(), 'onerror:', e.data || e);
|
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
|
// Most connection errors for WebSockets are conveyed as 'close' events with
|
||||||
// code 1006. This is done for security purposes and therefore unlikely to
|
// code 1006. This is done for security purposes and therefore unlikely to
|
||||||
// ever change.
|
// ever change.
|
||||||
@@ -545,6 +579,8 @@ Server.prototype._handleMessage = function(message) {
|
|||||||
Server.prototype._handleLedgerClosed = function(message) {
|
Server.prototype._handleLedgerClosed = function(message) {
|
||||||
this._lastLedgerIndex = message.ledger_index;
|
this._lastLedgerIndex = message.ledger_index;
|
||||||
this._lastLedgerClose = Date.now();
|
this._lastLedgerClose = Date.now();
|
||||||
|
this._ledgerRanges.add(message.ledger_index);
|
||||||
|
this._ledgerMap.set(message.ledger_hash, message.ledger_index);
|
||||||
this.emit('ledger_closed', message);
|
this.emit('ledger_closed', message);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -620,24 +656,33 @@ Server.prototype._handlePathFind = function(message) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle subscription response messages. Subscription response
|
* Handle initial subscription response message. The server is considered
|
||||||
* messages indicate that a connection to the server is ready
|
* `connected` after it has received a response to initial subscription to
|
||||||
|
* ledger and server streams
|
||||||
*
|
*
|
||||||
* @param {Object} message
|
* @param {Object} message
|
||||||
* @api private
|
* @api private
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Server.prototype._handleResponseSubscribe = function(message) {
|
Server.prototype._handleResponseSubscribe = function(message) {
|
||||||
if (!this._remote._allow_partial_history
|
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.hasFullLedgerHistory(message)) {
|
||||||
// Server has partial history and Remote has been configured to disallow
|
// Server has partial history and Remote has been configured to disallow
|
||||||
// servers with incomplete history
|
// servers with incomplete history
|
||||||
return this.reconnect();
|
return this.reconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.pubkey_node) {
|
if (message.pubkey_node) {
|
||||||
// pubkey_node is used to identify the server
|
// pubkey_node is used to identify the server
|
||||||
this._pubkey_node = message.pubkey_node;
|
this._pubkey_node = message.pubkey_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Server.isLoadStatus(message)) {
|
if (Server.isLoadStatus(message)) {
|
||||||
this._load_base = message.load_base || 256;
|
this._load_base = message.load_base || 256;
|
||||||
this._load_factor = message.load_factor || 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_base = message.reserve_base;
|
||||||
this._reserve_inc = message.reserve_inc;
|
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)) {
|
if (~Server.onlineStates.indexOf(message.server_status)) {
|
||||||
this._setState('online');
|
this._setState('online');
|
||||||
}
|
}
|
||||||
@@ -750,6 +801,12 @@ Server.prototype._request = function(request) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get server connected status
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
|
||||||
Server.prototype.isConnected =
|
Server.prototype.isConnected =
|
||||||
Server.prototype._isConnected = function() {
|
Server.prototype._isConnected = function() {
|
||||||
return this._connected;
|
return this._connected;
|
||||||
@@ -824,6 +881,36 @@ Server.prototype._reserve = function(ownerCount) {
|
|||||||
return reserve_base.add(reserve_inc.product_human(owner_count));
|
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;
|
exports.Server = Server;
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
// vim:sw=2:sts=2:ts=8:et
|
||||||
|
|||||||
@@ -1,30 +1,19 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var sjcl = require('./utils').sjcl;
|
|
||||||
var stypes = require('./serializedtypes');
|
|
||||||
var hashprefixes = require('./hashprefixes');
|
var hashprefixes = require('./hashprefixes');
|
||||||
|
|
||||||
var UInt256 = require('./uint256').UInt256;
|
var UInt256 = require('./uint256').UInt256;
|
||||||
var SerializedObject = require('./serializedobject').SerializedObject;
|
var SerializedObject = require('./serializedobject').SerializedObject;
|
||||||
|
|
||||||
function SHAMap() {
|
|
||||||
this.root = new SHAMapTreeNodeInner(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
SHAMap.prototype.add_item = function(tag, node, type) {
|
|
||||||
var node = new SHAMapTreeNodeLeaf(tag, node, type);
|
|
||||||
this.root.add_item(tag, node);
|
|
||||||
};
|
|
||||||
|
|
||||||
SHAMap.prototype.hash = function() {
|
|
||||||
return this.root.hash();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class representing a node in a SHAMap tree.
|
* Abstract class representing a node in a SHAMap tree.
|
||||||
*
|
*
|
||||||
* Can be either SHAMapTreeNodeInner or SHAMapTreeNodeLeaf.
|
* Can be either SHAMapTreeNodeInner or SHAMapTreeNodeLeaf.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
*/
|
*/
|
||||||
function SHAMapTreeNode() { };
|
function SHAMapTreeNode() { }
|
||||||
|
|
||||||
SHAMapTreeNode.TYPE_INNER = 1;
|
SHAMapTreeNode.TYPE_INNER = 1;
|
||||||
SHAMapTreeNode.TYPE_TRANSACTION_NM = 2;
|
SHAMapTreeNode.TYPE_TRANSACTION_NM = 2;
|
||||||
@@ -32,11 +21,17 @@ SHAMapTreeNode.TYPE_TRANSACTION_MD = 3;
|
|||||||
SHAMapTreeNode.TYPE_ACCOUNT_STATE = 4;
|
SHAMapTreeNode.TYPE_ACCOUNT_STATE = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tag {String} 64 hexadecimal characters
|
* @param {String} tag (64 hexadecimal characters)
|
||||||
|
* @param {SHAMapTreeNode} node
|
||||||
|
* @return {void}
|
||||||
|
* @virtual
|
||||||
*/
|
*/
|
||||||
|
/*eslint-disable no-unused-vars*/
|
||||||
SHAMapTreeNode.prototype.add_item = function(tag, node) {
|
SHAMapTreeNode.prototype.add_item = function(tag, node) {
|
||||||
throw new Error('Called unimplemented virtual method SHAMapTreeNode#add_item.');
|
throw new Error(
|
||||||
|
'Called unimplemented virtual method SHAMapTreeNode#add_item.');
|
||||||
};
|
};
|
||||||
|
/*eslint-enable no-unused-vars*/
|
||||||
|
|
||||||
SHAMapTreeNode.prototype.hash = function() {
|
SHAMapTreeNode.prototype.hash = function() {
|
||||||
throw new Error('Called unimplemented virtual method SHAMapTreeNode#hash.');
|
throw new Error('Called unimplemented virtual method SHAMapTreeNode#hash.');
|
||||||
@@ -44,6 +39,8 @@ SHAMapTreeNode.prototype.hash = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Inner (non-leaf) node in a SHAMap tree.
|
* Inner (non-leaf) node in a SHAMap tree.
|
||||||
|
* @param {Number} depth (i.e. how many parent inner nodes)
|
||||||
|
* @class
|
||||||
*/
|
*/
|
||||||
function SHAMapTreeNodeInner(depth) {
|
function SHAMapTreeNodeInner(depth) {
|
||||||
SHAMapTreeNode.call(this);
|
SHAMapTreeNode.call(this);
|
||||||
@@ -51,7 +48,7 @@ function SHAMapTreeNodeInner(depth) {
|
|||||||
this.leaves = {};
|
this.leaves = {};
|
||||||
|
|
||||||
this.type = SHAMapTreeNode.INNER;
|
this.type = SHAMapTreeNode.INNER;
|
||||||
this.depth = depth == null ? 0 : depth;
|
this.depth = depth === undefined ? 0 : depth;
|
||||||
|
|
||||||
this.empty = true;
|
this.empty = true;
|
||||||
}
|
}
|
||||||
@@ -59,7 +56,9 @@ function SHAMapTreeNodeInner(depth) {
|
|||||||
util.inherits(SHAMapTreeNodeInner, SHAMapTreeNode);
|
util.inherits(SHAMapTreeNodeInner, SHAMapTreeNode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tag {String} (equates to a ledger entries `index`)
|
* @param {String} tag (equates to a ledger entry `index`)
|
||||||
|
* @param {SHAMapTreeNode} node (to add)
|
||||||
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
SHAMapTreeNodeInner.prototype.add_item = function(tag, node) {
|
SHAMapTreeNodeInner.prototype.add_item = function(tag, node) {
|
||||||
var depth = this.depth;
|
var depth = this.depth;
|
||||||
@@ -72,7 +71,8 @@ SHAMapTreeNodeInner.prototype.add_item = function (tag, node) {
|
|||||||
existing_node.add_item(tag, node);
|
existing_node.add_item(tag, node);
|
||||||
} else if (existing_node.tag === tag) {
|
} else if (existing_node.tag === tag) {
|
||||||
// Collision
|
// Collision
|
||||||
throw new Error('Tried to add a node to a SHAMap that was already in there.');
|
throw new Error(
|
||||||
|
'Tried to add a node to a SHAMap that was already in there.');
|
||||||
} else {
|
} else {
|
||||||
// Turn it into an inner node
|
// Turn it into an inner node
|
||||||
var new_inner_node = new SHAMapTreeNodeInner(depth + 1);
|
var new_inner_node = new SHAMapTreeNodeInner(depth + 1);
|
||||||
@@ -92,6 +92,9 @@ SHAMapTreeNodeInner.prototype.add_item = function (tag, node) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Overwrite the node that is currently in a given slot.
|
* Overwrite the node that is currently in a given slot.
|
||||||
|
* @param {String} slot (a character 0-F)
|
||||||
|
* @param {SHAMapTreeNode} node (to place)
|
||||||
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
SHAMapTreeNodeInner.prototype.set_node = function(slot, node) {
|
SHAMapTreeNodeInner.prototype.set_node = function(slot, node) {
|
||||||
this.leaves[slot] = node;
|
this.leaves[slot] = node;
|
||||||
@@ -108,7 +111,6 @@ SHAMapTreeNodeInner.prototype.hash = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hash_buffer = new SerializedObject();
|
var hash_buffer = new SerializedObject();
|
||||||
var buffer = [ ];
|
|
||||||
|
|
||||||
for (var i = 0; i < 16; i++) {
|
for (var i = 0; i < 16; i++) {
|
||||||
var leafHash = UInt256.from_hex(UInt256.HEX_ZERO);
|
var leafHash = UInt256.from_hex(UInt256.HEX_ZERO);
|
||||||
@@ -128,6 +130,10 @@ SHAMapTreeNodeInner.prototype.hash = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Leaf node in a SHAMap tree.
|
* Leaf node in a SHAMap tree.
|
||||||
|
* @param {String} tag (equates to a ledger entry `index`)
|
||||||
|
* @param {SerializedObject} node (bytes of account state, transaction etc)
|
||||||
|
* @param {Number} type (one of TYPE_ACCOUNT_STATE, TYPE_TRANSACTION_MD etc)
|
||||||
|
* @class
|
||||||
*/
|
*/
|
||||||
function SHAMapTreeNodeLeaf(tag, node, type) {
|
function SHAMapTreeNodeLeaf(tag, node, type) {
|
||||||
SHAMapTreeNode.call(this);
|
SHAMapTreeNode.call(this);
|
||||||
@@ -140,7 +146,7 @@ function SHAMapTreeNodeLeaf(tag, node, type) {
|
|||||||
this.tag_bytes = UInt256.from_hex(this.tag).to_bytes();
|
this.tag_bytes = UInt256.from_hex(this.tag).to_bytes();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
};
|
}
|
||||||
|
|
||||||
util.inherits(SHAMapTreeNodeLeaf, SHAMapTreeNode);
|
util.inherits(SHAMapTreeNodeLeaf, SHAMapTreeNode);
|
||||||
|
|
||||||
@@ -162,6 +168,19 @@ SHAMapTreeNodeLeaf.prototype.hash = function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function SHAMap() {
|
||||||
|
this.root = new SHAMapTreeNodeInner(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAMap.prototype.add_item = function(tag, node, type) {
|
||||||
|
node = new SHAMapTreeNodeLeaf(tag, node, type);
|
||||||
|
this.root.add_item(tag, node);
|
||||||
|
};
|
||||||
|
|
||||||
|
SHAMap.prototype.hash = function() {
|
||||||
|
return this.root.hash();
|
||||||
|
};
|
||||||
|
|
||||||
exports.SHAMap = SHAMap;
|
exports.SHAMap = SHAMap;
|
||||||
exports.SHAMapTreeNode = SHAMapTreeNode;
|
exports.SHAMapTreeNode = SHAMapTreeNode;
|
||||||
exports.SHAMapTreeNodeInner = SHAMapTreeNodeInner;
|
exports.SHAMapTreeNodeInner = SHAMapTreeNodeInner;
|
||||||
|
|||||||
@@ -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;
|
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var assert = require('assert');
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var sjcl = require('./utils').sjcl;
|
var sjcl = require('./utils').sjcl;
|
||||||
@@ -11,6 +12,7 @@ var SerializedObject = require('./serializedobject').SerializedObject;
|
|||||||
var RippleError = require('./rippleerror').RippleError;
|
var RippleError = require('./rippleerror').RippleError;
|
||||||
var hashprefixes = require('./hashprefixes');
|
var hashprefixes = require('./hashprefixes');
|
||||||
var config = require('./config');
|
var config = require('./config');
|
||||||
|
var log = require('./log').internal.sub('transaction');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor Transaction
|
* @constructor Transaction
|
||||||
@@ -35,13 +37,13 @@ function Transaction(remote) {
|
|||||||
|
|
||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
this.tx_json = {Flags: 0};
|
this.tx_json = {Flags: 0};
|
||||||
this._secret = void(0);
|
this._secret = undefined;
|
||||||
this._build_path = false;
|
this._build_path = false;
|
||||||
this._maxFee = remoteExists ? this.remote.max_fee : void(0);
|
this._maxFee = remoteExists ? this.remote.max_fee : undefined;
|
||||||
this.state = 'unsubmitted';
|
this.state = 'unsubmitted';
|
||||||
this.finalized = false;
|
this.finalized = false;
|
||||||
this.previousSigningHash = void(0);
|
this.previousSigningHash = undefined;
|
||||||
this.submitIndex = void(0);
|
this.submitIndex = undefined;
|
||||||
this.canonical = remoteExists ? this.remote.canonical_signing : true;
|
this.canonical = remoteExists ? this.remote.canonical_signing : true;
|
||||||
this.submittedIDs = [ ];
|
this.submittedIDs = [ ];
|
||||||
this.attempts = 0;
|
this.attempts = 0;
|
||||||
@@ -75,11 +77,12 @@ function Transaction(remote) {
|
|||||||
// Transaction was submitted successfully to the network
|
// Transaction was submitted successfully to the network
|
||||||
self.setState('pending');
|
self.setState('pending');
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
util.inherits(Transaction, EventEmitter);
|
util.inherits(Transaction, EventEmitter);
|
||||||
|
|
||||||
// XXX This needs to be determined from the network.
|
// This is currently a constant in rippled known as the "base reference"
|
||||||
|
// https://wiki.ripple.com/Transaction_Fee#Base_Fees
|
||||||
Transaction.fee_units = {
|
Transaction.fee_units = {
|
||||||
default: 10
|
default: 10
|
||||||
};
|
};
|
||||||
@@ -131,8 +134,10 @@ Transaction.set_clear_flags = {
|
|||||||
asfRequireAuth: 2,
|
asfRequireAuth: 2,
|
||||||
asfDisallowXRP: 3,
|
asfDisallowXRP: 3,
|
||||||
asfDisableMaster: 4,
|
asfDisableMaster: 4,
|
||||||
|
asfAccountTxnID: 5,
|
||||||
asfNoFreeze: 6,
|
asfNoFreeze: 6,
|
||||||
asfGlobalFreeze: 7
|
asfGlobalFreeze: 7,
|
||||||
|
asfDefaultRipple: 8
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -177,7 +182,9 @@ Transaction.prototype.isTecClaimed = function(ter) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Transaction.prototype.isRejected = function(ter) {
|
Transaction.prototype.isRejected = function(ter) {
|
||||||
return this.isTelLocal(ter) || this.isTemMalformed(ter) || this.isTefFailure(ter);
|
return this.isTelLocal(ter) ||
|
||||||
|
this.isTemMalformed(ter) ||
|
||||||
|
this.isTefFailure(ter);
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction.from_json = function(j) {
|
Transaction.from_json = function(j) {
|
||||||
@@ -260,7 +267,7 @@ Transaction.prototype.getTransactionType = function() {
|
|||||||
|
|
||||||
Transaction.prototype.getManager = function(account) {
|
Transaction.prototype.getManager = function(account) {
|
||||||
if (!this.remote) {
|
if (!this.remote) {
|
||||||
return void(0);
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
@@ -279,7 +286,7 @@ Transaction.prototype.getManager = function(account) {
|
|||||||
Transaction.prototype.getSecret =
|
Transaction.prototype.getSecret =
|
||||||
Transaction.prototype._accountSecret = function(account) {
|
Transaction.prototype._accountSecret = function(account) {
|
||||||
if (!this.remote) {
|
if (!this.remote) {
|
||||||
return void(0);
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
@@ -303,7 +310,7 @@ Transaction.prototype._accountSecret = function(account) {
|
|||||||
|
|
||||||
Transaction.prototype._getFeeUnits =
|
Transaction.prototype._getFeeUnits =
|
||||||
Transaction.prototype.feeUnits = function() {
|
Transaction.prototype.feeUnits = function() {
|
||||||
return Transaction.fee_units['default'];
|
return Transaction.fee_units.default;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -314,7 +321,7 @@ Transaction.prototype.feeUnits = function() {
|
|||||||
|
|
||||||
Transaction.prototype._computeFee = function() {
|
Transaction.prototype._computeFee = function() {
|
||||||
if (!this.remote) {
|
if (!this.remote) {
|
||||||
return void(0);
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
var servers = this.remote._servers;
|
var servers = this.remote._servers;
|
||||||
@@ -328,7 +335,7 @@ Transaction.prototype._computeFee = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (fees.length) {
|
switch (fees.length) {
|
||||||
case 0: return;
|
case 0: return undefined;
|
||||||
case 1: return String(fees[0]);
|
case 1: return String(fees[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,9 +344,8 @@ Transaction.prototype._computeFee = function() {
|
|||||||
return 1;
|
return 1;
|
||||||
} else if (a < b) {
|
} else if (a < b) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
var midInd = Math.floor(fees.length / 2);
|
var midInd = Math.floor(fees.length / 2);
|
||||||
@@ -371,8 +377,12 @@ Transaction.prototype.complete = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this._secret) {
|
||||||
|
this._secret = this.getSecret();
|
||||||
|
}
|
||||||
|
|
||||||
// Try to auto-fill the secret
|
// Try to auto-fill the secret
|
||||||
if (!this._secret && !(this._secret = this.getSecret())) {
|
if (!this._secret) {
|
||||||
this.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
|
this.emit('error', new RippleError('tejSecretUnknown', 'Missing secret'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -393,7 +403,8 @@ Transaction.prototype.complete = function() {
|
|||||||
// an assigned server
|
// an assigned server
|
||||||
if (this.remote && typeof this.tx_json.Fee === 'undefined') {
|
if (this.remote && typeof this.tx_json.Fee === 'undefined') {
|
||||||
if (this.remote.local_fee || !this.remote.trusted) {
|
if (this.remote.local_fee || !this.remote.trusted) {
|
||||||
if (!(this.tx_json.Fee = this._computeFee())) {
|
this.tx_json.Fee = this._computeFee();
|
||||||
|
if (!this.tx_json.Fee) {
|
||||||
this.emit('error', new RippleError('tejUnconnected'));
|
this.emit('error', new RippleError('tejUnconnected'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -456,7 +467,7 @@ Transaction.prototype.sign = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var key = seed.get_key(this.tx_json.Account);
|
var key = seed.get_key(this.tx_json.Account);
|
||||||
var sig = key.sign(hash, 0);
|
var sig = key.sign(hash);
|
||||||
var hex = sjcl.codec.hex.fromBits(sig).toUpperCase();
|
var hex = sjcl.codec.hex.fromBits(sig).toUpperCase();
|
||||||
|
|
||||||
this.tx_json.TxnSignature = hex;
|
this.tx_json.TxnSignature = hex;
|
||||||
@@ -775,7 +786,7 @@ Transaction.prototype.transferRate = function(rate) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Transaction.prototype.setFlags = function(flags) {
|
Transaction.prototype.setFlags = function(flags) {
|
||||||
if (flags === void(0)) {
|
if (flags === undefined) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -833,24 +844,42 @@ Transaction.prototype.addMemo = function(memoType, memoFormat, memoData) {
|
|||||||
throw new Error('MemoFormat must be valid ASCII');
|
throw new Error('MemoFormat must be valid ASCII');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertStringToHex(string) {
|
||||||
|
var utf8String = sjcl.codec.utf8String.toBits(string);
|
||||||
|
return sjcl.codec.hex.fromBits(utf8String).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
var memo = {};
|
var memo = {};
|
||||||
|
|
||||||
if (memoType) {
|
if (memoType) {
|
||||||
if (Transaction.MEMO_TYPES[memoType]) {
|
if (Transaction.MEMO_TYPES[memoType]) {
|
||||||
// XXX Maybe in the future we want a schema validator for
|
// XXX Maybe in the future we want a schema validator for
|
||||||
// memo types
|
// memo types
|
||||||
memo.MemoType = Transaction.MEMO_TYPES[memoType];
|
memoType = Transaction.MEMO_TYPES[memoType];
|
||||||
} else {
|
|
||||||
memo.MemoType = memoType;
|
|
||||||
}
|
}
|
||||||
|
memo.MemoType = convertStringToHex(memoType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memoFormat) {
|
if (memoFormat) {
|
||||||
memo.MemoFormat = memoFormat;
|
memo.MemoFormat = convertStringToHex(memoFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memoData) {
|
if (memoData) {
|
||||||
memo.MemoData = memoData;
|
if (typeof memoData !== 'string') {
|
||||||
|
if (memoFormat === 'json') {
|
||||||
|
try {
|
||||||
|
memoData = JSON.stringify(memoData);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(
|
||||||
|
'MemoFormat json with invalid JSON in MemoData field');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'MemoData can only be a JSON object with a valid json MemoFormat');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memo.MemoData = convertStringToHex(memoData);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tx_json.Memos = (this.tx_json.Memos || []).concat({Memo: memo});
|
this.tx_json.Memos = (this.tx_json.Memos || []).concat({Memo: memo});
|
||||||
@@ -858,6 +887,15 @@ Transaction.prototype.addMemo = function(memoType, memoFormat, memoData) {
|
|||||||
return this;
|
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
|
* Construct an 'AccountSet' transaction
|
||||||
*
|
*
|
||||||
@@ -898,14 +936,24 @@ Transaction.prototype.accountSet = function(src, set_flag, clear_flag) {
|
|||||||
return (typeof flag === 'number')
|
return (typeof flag === 'number')
|
||||||
? flag
|
? flag
|
||||||
: (SetClearFlags[flag] || SetClearFlags['asf' + flag]);
|
: (SetClearFlags[flag] || SetClearFlags['asf' + flag]);
|
||||||
};
|
|
||||||
|
|
||||||
if (set_flag && (set_flag = prepareFlag(set_flag))) {
|
|
||||||
this.tx_json.SetFlag = set_flag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clear_flag && (clear_flag = prepareFlag(clear_flag))) {
|
var prepared;
|
||||||
this.tx_json.ClearFlag = clear_flag;
|
|
||||||
|
if (set_flag) {
|
||||||
|
prepared = prepareFlag(set_flag);
|
||||||
|
|
||||||
|
if (prepared) {
|
||||||
|
this.tx_json.SetFlag = prepared;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_flag) {
|
||||||
|
prepared = prepareFlag(clear_flag);
|
||||||
|
|
||||||
|
if (prepared) {
|
||||||
|
this.tx_json.ClearFlag = prepared;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -967,7 +1015,8 @@ Transaction.prototype.offerCancel = function(src, sequence) {
|
|||||||
* @param [Number] sequence of an existing offer to replace
|
* @param [Number] sequence of an existing offer to replace
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Transaction.prototype.offerCreate = function(src, taker_pays, taker_gets, expiration, cancel_sequence) {
|
Transaction.prototype.offerCreate = function(src, taker_pays, taker_gets,
|
||||||
|
expiration, cancel_sequence) {
|
||||||
if (typeof src === 'object') {
|
if (typeof src === 'object') {
|
||||||
var options = src;
|
var options = src;
|
||||||
cancel_sequence = options.cancel_sequence || options.sequence;
|
cancel_sequence = options.cancel_sequence || options.sequence;
|
||||||
@@ -1083,7 +1132,10 @@ Transaction.prototype.payment = function(src, dst, amount) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Transaction.prototype.trustSet =
|
Transaction.prototype.trustSet =
|
||||||
Transaction.prototype.rippleLineSet = function(src, limit, quality_in, quality_out) {
|
Transaction.prototype.rippleLineSet = function(src,
|
||||||
|
limit,
|
||||||
|
quality_in,
|
||||||
|
quality_out) {
|
||||||
if (typeof src === 'object') {
|
if (typeof src === 'object') {
|
||||||
var options = src;
|
var options = src;
|
||||||
quality_out = options.quality_out;
|
quality_out = options.quality_out;
|
||||||
@@ -1099,7 +1151,7 @@ Transaction.prototype.rippleLineSet = function(src, limit, quality_in, quality_o
|
|||||||
this.tx_json.TransactionType = 'TrustSet';
|
this.tx_json.TransactionType = 'TrustSet';
|
||||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||||
|
|
||||||
if (limit !== void(0)) {
|
if (limit !== undefined) {
|
||||||
this.tx_json.LimitAmount = Amount.json_rewrite(limit);
|
this.tx_json.LimitAmount = Amount.json_rewrite(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1140,7 +1192,7 @@ Transaction.prototype.submit = function(callback) {
|
|||||||
|
|
||||||
if (!this.remote) {
|
if (!this.remote) {
|
||||||
this.emit('error', new Error('No remote found'));
|
this.emit('error', new Error('No remote found'));
|
||||||
return;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getManager().submit(this);
|
this.getManager().submit(this);
|
||||||
@@ -1170,7 +1222,7 @@ Transaction.prototype.summary = function() {
|
|||||||
initialSubmitIndex: this.initialSubmitIndex,
|
initialSubmitIndex: this.initialSubmitIndex,
|
||||||
lastLedgerSequence: this.lastLedgerSequence,
|
lastLedgerSequence: this.lastLedgerSequence,
|
||||||
state: this.state,
|
state: this.state,
|
||||||
server: this._server ? this._server._opts.url : void(0),
|
server: this._server ? this._server._opts.url : undefined,
|
||||||
finalized: this.finalized
|
finalized: this.finalized
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
@@ -20,11 +22,11 @@ function TransactionManager(account) {
|
|||||||
this._account = account;
|
this._account = account;
|
||||||
this._accountID = account._account_id;
|
this._accountID = account._account_id;
|
||||||
this._remote = account._remote;
|
this._remote = account._remote;
|
||||||
this._nextSequence = void(0);
|
this._nextSequence = undefined;
|
||||||
this._maxFee = this._remote.max_fee;
|
this._maxFee = this._remote.max_fee;
|
||||||
this._maxAttempts = this._remote.max_attempts;
|
this._maxAttempts = this._remote.max_attempts;
|
||||||
this._submissionTimeout = this._remote._submission_timeout;
|
this._submissionTimeout = this._remote.submission_timeout;
|
||||||
this._lastLedgerOffset = this._remote._last_ledger_offset;
|
this._lastLedgerOffset = this._remote.last_ledger_offset;
|
||||||
this._pending = new PendingQueue();
|
this._pending = new PendingQueue();
|
||||||
|
|
||||||
this._account.on('transaction-outbound', function(res) {
|
this._account.on('transaction-outbound', function(res) {
|
||||||
@@ -37,7 +39,7 @@ function TransactionManager(account) {
|
|||||||
|
|
||||||
function updatePendingStatus(ledger) {
|
function updatePendingStatus(ledger) {
|
||||||
self._updatePendingStatus(ledger);
|
self._updatePendingStatus(ledger);
|
||||||
};
|
}
|
||||||
|
|
||||||
this._remote.on('ledger_closed', updatePendingStatus);
|
this._remote.on('ledger_closed', updatePendingStatus);
|
||||||
|
|
||||||
@@ -47,7 +49,7 @@ function TransactionManager(account) {
|
|||||||
// hooking back into ledger_closed
|
// hooking back into ledger_closed
|
||||||
self._remote.on('ledger_closed', updatePendingStatus);
|
self._remote.on('ledger_closed', updatePendingStatus);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
this._remote.on('disconnect', function() {
|
this._remote.on('disconnect', function() {
|
||||||
self._remote.removeListener('ledger_closed', updatePendingStatus);
|
self._remote.removeListener('ledger_closed', updatePendingStatus);
|
||||||
@@ -56,7 +58,7 @@ function TransactionManager(account) {
|
|||||||
|
|
||||||
// Query server for next account transaction sequence
|
// Query server for next account transaction sequence
|
||||||
this._loadSequence();
|
this._loadSequence();
|
||||||
};
|
}
|
||||||
|
|
||||||
util.inherits(TransactionManager, EventEmitter);
|
util.inherits(TransactionManager, EventEmitter);
|
||||||
|
|
||||||
@@ -162,7 +164,8 @@ TransactionManager.prototype._transactionReceived = function(tx) {
|
|||||||
|
|
||||||
if (!(submission instanceof Transaction)) {
|
if (!(submission instanceof Transaction)) {
|
||||||
// The received transaction does not correlate to one submitted
|
// The received transaction does not correlate to one submitted
|
||||||
return this._pending.addReceivedId(hash, transaction);
|
this._pending.addReceivedId(hash, transaction);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ND: A `success` handler will `finalize` this later
|
// ND: A `success` handler will `finalize` this later
|
||||||
@@ -197,7 +200,7 @@ TransactionManager.prototype._adjustFees = function() {
|
|||||||
transaction.once('presubmit', function() {
|
transaction.once('presubmit', function() {
|
||||||
transaction.emit('error', 'tejMaxFeeExceeded');
|
transaction.emit('error', 'tejMaxFeeExceeded');
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
this._pending.forEach(function(transaction) {
|
this._pending.forEach(function(transaction) {
|
||||||
if (transaction._setFixedFee) {
|
if (transaction._setFixedFee) {
|
||||||
@@ -209,7 +212,8 @@ TransactionManager.prototype._adjustFees = function() {
|
|||||||
|
|
||||||
if (Number(newFee) > self._maxFee) {
|
if (Number(newFee) > self._maxFee) {
|
||||||
// Max transaction fee exceeded, abort submission
|
// Max transaction fee exceeded, abort submission
|
||||||
return maxFeeExceeded(transaction);
|
maxFeeExceeded(transaction);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.tx_json.Fee = newFee;
|
transaction.tx_json.Fee = newFee;
|
||||||
@@ -244,6 +248,10 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
|||||||
assert.strictEqual(typeof ledger.ledger_index, 'number');
|
assert.strictEqual(typeof ledger.ledger_index, 'number');
|
||||||
|
|
||||||
this._pending.forEach(function(transaction) {
|
this._pending.forEach(function(transaction) {
|
||||||
|
if (transaction.finalized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (ledger.ledger_index - transaction.submitIndex) {
|
switch (ledger.ledger_index - transaction.submitIndex) {
|
||||||
case 4:
|
case 4:
|
||||||
transaction.emit('missing', ledger);
|
transaction.emit('missing', ledger);
|
||||||
@@ -253,10 +261,6 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transaction.finalized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ledger.ledger_index > transaction.tx_json.LastLedgerSequence) {
|
if (ledger.ledger_index > transaction.tx_json.LastLedgerSequence) {
|
||||||
// Transaction must fail
|
// Transaction must fail
|
||||||
transaction.emit('error', new RippleError(
|
transaction.emit('error', new RippleError(
|
||||||
@@ -269,42 +273,50 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
|
|||||||
TransactionManager.prototype._fillSequence = function(tx, callback) {
|
TransactionManager.prototype._fillSequence = function(tx, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function submitFill(sequence, callback) {
|
function submitFill(sequence, fCallback) {
|
||||||
var fill = self._remote.transaction();
|
var fillTransaction = self._remote.createTransaction('AccountSet', {
|
||||||
fill.account_set(self._accountID);
|
account: self._accountID
|
||||||
fill.tx_json.Sequence = sequence;
|
});
|
||||||
fill.once('submitted', callback);
|
fillTransaction.tx_json.Sequence = sequence;
|
||||||
|
|
||||||
// Secrets may be set on a per-transaction basis
|
// Secrets may be set on a per-transaction basis
|
||||||
if (tx._secret) {
|
if (tx._secret) {
|
||||||
fill.secret(tx._secret);
|
fillTransaction.secret(tx._secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
fill.submit();
|
fillTransaction.once('submitted', fCallback);
|
||||||
};
|
fillTransaction.submit();
|
||||||
|
}
|
||||||
|
|
||||||
function sequenceLoaded(err, sequence) {
|
function sequenceLoaded(err, sequence) {
|
||||||
if (typeof sequence !== 'number') {
|
if (typeof sequence !== 'number') {
|
||||||
return callback(new Error('Failed to fetch account transaction sequence'));
|
log.info('fill sequence: failed to fetch account transaction sequence');
|
||||||
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
var sequenceDif = tx.tx_json.Sequence - sequence;
|
var sequenceDiff = tx.tx_json.Sequence - sequence;
|
||||||
var submitted = 0;
|
var submitted = 0;
|
||||||
|
|
||||||
;(function nextFill(sequence) {
|
async.whilst(
|
||||||
if (sequence >= tx.tx_json.Sequence) {
|
function() {
|
||||||
return;
|
return submitted < sequenceDiff;
|
||||||
}
|
},
|
||||||
|
function(asyncCallback) {
|
||||||
submitFill(sequence, function() {
|
submitFill(sequence, function(res) {
|
||||||
if (++submitted === sequenceDif) {
|
++submitted;
|
||||||
callback();
|
if (res.engine_result === 'tesSUCCESS') {
|
||||||
} else {
|
self.emit('sequence_filled', err);
|
||||||
nextFill(sequence + 1);
|
|
||||||
}
|
}
|
||||||
|
asyncCallback();
|
||||||
});
|
});
|
||||||
})(sequence);
|
},
|
||||||
};
|
function() {
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this._loadSequence(sequenceLoaded);
|
this._loadSequence(sequenceLoaded);
|
||||||
};
|
};
|
||||||
@@ -318,7 +330,7 @@ TransactionManager.prototype._fillSequence = function(tx, callback) {
|
|||||||
|
|
||||||
TransactionManager.prototype._loadSequence = function(callback) {
|
TransactionManager.prototype._loadSequence = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var callback = (typeof callback === 'function') ? callback : function(){};
|
callback = (typeof callback === 'function') ? callback : function() {};
|
||||||
|
|
||||||
function sequenceLoaded(err, sequence) {
|
function sequenceLoaded(err, sequence) {
|
||||||
if (err || typeof sequence !== 'number') {
|
if (err || typeof sequence !== 'number') {
|
||||||
@@ -331,7 +343,7 @@ TransactionManager.prototype._loadSequence = function(callback) {
|
|||||||
self._nextSequence = sequence;
|
self._nextSequence = sequence;
|
||||||
self.emit('sequence_loaded', sequence);
|
self.emit('sequence_loaded', sequence);
|
||||||
callback(err, sequence);
|
callback(err, sequence);
|
||||||
};
|
}
|
||||||
|
|
||||||
this._account.getNextSequence(sequenceLoaded);
|
this._account.getNextSequence(sequenceLoaded);
|
||||||
};
|
};
|
||||||
@@ -346,10 +358,11 @@ TransactionManager.prototype._loadSequence = function(callback) {
|
|||||||
|
|
||||||
TransactionManager.prototype._handleReconnect = function(callback) {
|
TransactionManager.prototype._handleReconnect = function(callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var callback = (typeof callback === 'function') ? callback : function(){};
|
callback = (typeof callback === 'function') ? callback : function() {};
|
||||||
|
|
||||||
if (!this._pending.length()) {
|
if (!this._pending.length()) {
|
||||||
return callback();
|
callback();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTransactions(err, transactions) {
|
function handleTransactions(err, transactions) {
|
||||||
@@ -372,7 +385,7 @@ TransactionManager.prototype._handleReconnect = function(callback) {
|
|||||||
// Resubmit pending transactions after sequence is loaded
|
// Resubmit pending transactions after sequence is loaded
|
||||||
self._resubmit();
|
self._resubmit();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
account: this._accountID,
|
account: this._accountID,
|
||||||
@@ -410,7 +423,7 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
|
|||||||
self._remote.removeListener('ledger_closed', ledgerClosed);
|
self._remote.removeListener('ledger_closed', ledgerClosed);
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
this._remote.on('ledger_closed', ledgerClosed);
|
this._remote.on('ledger_closed', ledgerClosed);
|
||||||
};
|
};
|
||||||
@@ -426,8 +439,16 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
|
|||||||
|
|
||||||
TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var ledgers = ledgers || 0;
|
|
||||||
var pending = pending ? [ pending ] : this._pending;
|
if (ledgers && typeof ledgers !== 'number') {
|
||||||
|
pending = ledgers;
|
||||||
|
ledgers = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ledgers = ledgers || 0;
|
||||||
|
pending = pending instanceof Transaction
|
||||||
|
? [pending]
|
||||||
|
: this.getPending().getQueue();
|
||||||
|
|
||||||
function resubmitTransaction(transaction, next) {
|
function resubmitTransaction(transaction, next) {
|
||||||
if (!transaction || transaction.finalized) {
|
if (!transaction || transaction.finalized) {
|
||||||
@@ -439,7 +460,13 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
|||||||
var received = transaction.findId(self._pending._idCache);
|
var received = transaction.findId(self._pending._idCache);
|
||||||
|
|
||||||
if (received) {
|
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)) {
|
while (self._pending.hasSequence(transaction.tx_json.Sequence)) {
|
||||||
@@ -461,7 +488,7 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
self._request(transaction);
|
self._request(transaction);
|
||||||
};
|
}
|
||||||
|
|
||||||
this._waitLedgers(ledgers, function() {
|
this._waitLedgers(ledgers, function() {
|
||||||
async.eachSeries(pending, resubmitTransaction);
|
async.eachSeries(pending, resubmitTransaction);
|
||||||
@@ -522,8 +549,8 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tx.attempts > 0 && !remote.local_signing) {
|
if (tx.attempts > 0 && !remote.local_signing) {
|
||||||
var message = 'Automatic resubmission requires local signing';
|
var errMessage = 'Automatic resubmission requires local signing';
|
||||||
tx.emit('error', new RippleError('tejLocalSigningRequired', message));
|
tx.emit('error', new RippleError('tejLocalSigningRequired', errMessage));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,22 +563,22 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
// Transaction may succeed after Sequence is updated
|
// Transaction may succeed after Sequence is updated
|
||||||
self._resubmit(1, tx);
|
self._resubmit(1, tx);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function transactionRetry(message) {
|
function transactionRetry() {
|
||||||
// XXX This may no longer be necessary. Instead, update sequence numbers
|
// XXX This may no longer be necessary. Instead, update sequence numbers
|
||||||
// after a transaction fails definitively
|
// after a transaction fails definitively
|
||||||
self._fillSequence(tx, function() {
|
self._fillSequence(tx, function() {
|
||||||
self._resubmit(1, tx);
|
self._resubmit(1, tx);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function transactionFailedLocal(message) {
|
function transactionFailedLocal(message) {
|
||||||
if (message.engine_result === 'telINSUF_FEE_P') {
|
if (message.engine_result === 'telINSUF_FEE_P') {
|
||||||
// Transaction may succeed after Fee is updated
|
// Transaction may succeed after Fee is updated
|
||||||
self._resubmit(1, tx);
|
self._resubmit(1, tx);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function submissionError(error) {
|
function submissionError(error) {
|
||||||
// Either a tem-class error or generic server error such as tooBusy. This
|
// Either a tem-class error or generic server error such as tooBusy. This
|
||||||
@@ -562,7 +589,7 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
self._nextSequence--;
|
self._nextSequence--;
|
||||||
tx.emit('error', error);
|
tx.emit('error', error);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function submitted(message) {
|
function submitted(message) {
|
||||||
if (tx.finalized) {
|
if (tx.finalized) {
|
||||||
@@ -605,7 +632,7 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
// tem
|
// tem
|
||||||
submissionError(message);
|
submissionError(message);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function requestTimeout() {
|
function requestTimeout() {
|
||||||
// ND: What if the response is just slow and we get a response that
|
// ND: What if the response is just slow and we get a response that
|
||||||
@@ -624,7 +651,7 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
}
|
}
|
||||||
self._resubmit(1, tx);
|
self._resubmit(1, tx);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
tx.submitIndex = this._remote._ledger_current_index;
|
tx.submitIndex = this._remote._ledger_current_index;
|
||||||
|
|
||||||
@@ -650,15 +677,12 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
|
|
||||||
tx.emit('presubmit');
|
tx.emit('presubmit');
|
||||||
|
|
||||||
tx.submissions = submitRequest.broadcast();
|
submitRequest.broadcast().request();
|
||||||
tx.attempts++;
|
tx.attempts++;
|
||||||
|
|
||||||
tx.emit('postsubmit');
|
tx.emit('postsubmit');
|
||||||
|
|
||||||
//XXX
|
|
||||||
submitRequest.timeout(self._submissionTimeout, requestTimeout);
|
submitRequest.timeout(self._submissionTimeout, requestTimeout);
|
||||||
|
|
||||||
return submitRequest;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -669,7 +693,6 @@ TransactionManager.prototype._request = function(tx) {
|
|||||||
|
|
||||||
TransactionManager.prototype.submit = function(tx) {
|
TransactionManager.prototype.submit = function(tx) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var remote = this._remote;
|
|
||||||
|
|
||||||
if (typeof this._nextSequence !== 'number') {
|
if (typeof this._nextSequence !== 'number') {
|
||||||
// If sequence number is not yet known, defer until it is.
|
// If sequence number is not yet known, defer until it is.
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var lodash = require('lodash');
|
||||||
var LRU = require('lru-cache');
|
var LRU = require('lru-cache');
|
||||||
var Transaction = require('./transaction').Transaction;
|
var Transaction = require('./transaction').Transaction;
|
||||||
|
|
||||||
@@ -7,9 +10,9 @@ var Transaction = require('./transaction').Transaction;
|
|||||||
|
|
||||||
function TransactionQueue() {
|
function TransactionQueue() {
|
||||||
this._queue = [ ];
|
this._queue = [ ];
|
||||||
this._idCache = LRU({ max: 200 });
|
this._idCache = new LRU({max: 200});
|
||||||
this._sequenceCache = LRU({ max: 200 });
|
this._sequenceCache = new LRU({max: 200});
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store received (validated) sequence
|
* Store received (validated) sequence
|
||||||
@@ -64,16 +67,9 @@ TransactionQueue.prototype.getReceived = function(id) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TransactionQueue.prototype.getSubmission = function(id) {
|
TransactionQueue.prototype.getSubmission = function(id) {
|
||||||
var result = void(0);
|
return lodash.find(this._queue, function(tx) {
|
||||||
|
return lodash.contains(tx.submittedIDs, id);
|
||||||
for (var i=0, tx; (tx=this._queue[i]); i++) {
|
});
|
||||||
if (~tx.submittedIDs.indexOf(id)) {
|
|
||||||
result = tx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,11 +79,15 @@ TransactionQueue.prototype.getSubmission = function(id) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TransactionQueue.prototype.getMinLedger = function() {
|
TransactionQueue.prototype.getMinLedger = function() {
|
||||||
|
if (this.length() < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
var result = Infinity;
|
var result = Infinity;
|
||||||
|
|
||||||
for (var i=0, tx; (tx=this._queue[i]); i++) {
|
for (var i = 0; i < this.length(); i++) {
|
||||||
if (tx.initialSubmitIndex < result) {
|
if (this._queue[i].initialSubmitIndex < result) {
|
||||||
result = tx.initialSubmitIndex;
|
result = this._queue[i].initialSubmitIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,4 +153,12 @@ TransactionQueue.prototype.getLength = function() {
|
|||||||
return this._queue.length;
|
return this._queue.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Array} pending queue
|
||||||
|
*/
|
||||||
|
|
||||||
|
TransactionQueue.prototype.getQueue = function() {
|
||||||
|
return this._queue;
|
||||||
|
};
|
||||||
|
|
||||||
exports.TransactionQueue = TransactionQueue;
|
exports.TransactionQueue = TransactionQueue;
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*eslint new-cap: 1*/
|
||||||
|
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var sjcl = utils.sjcl;
|
var sjcl = utils.sjcl;
|
||||||
var config = require('./config');
|
var config = require('./config');
|
||||||
|
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Abstract UInt class
|
// Abstract UInt class
|
||||||
//
|
//
|
||||||
// Base class for UInt classes
|
// Base class for UInt classes
|
||||||
//
|
//
|
||||||
|
|
||||||
var UInt = function() {
|
function UInt() {
|
||||||
// Internal form: NaN or BigInteger
|
// Internal form: NaN or sjcl.bn
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
|
|
||||||
this._update();
|
this._update();
|
||||||
};
|
}
|
||||||
|
|
||||||
UInt.json_rewrite = function(j, opts) {
|
UInt.json_rewrite = function(j, opts) {
|
||||||
return this.from_json(j).to_json(opts);
|
return this.from_json(j).to_json(opts);
|
||||||
@@ -25,63 +26,56 @@ UInt.json_rewrite = function(j, opts) {
|
|||||||
UInt.from_generic = function(j) {
|
UInt.from_generic = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_generic(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_generic(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a new UInt from j.
|
// Return a new UInt from j.
|
||||||
UInt.from_hex = function(j) {
|
UInt.from_hex = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_hex(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_hex(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a new UInt from j.
|
// Return a new UInt from j.
|
||||||
UInt.from_json = function(j) {
|
UInt.from_json = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_json(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_json(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a new UInt from j.
|
// Return a new UInt from j.
|
||||||
UInt.from_bits = function(j) {
|
UInt.from_bits = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_bits(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_bits(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a new UInt from j.
|
// Return a new UInt from j.
|
||||||
UInt.from_bytes = function(j) {
|
UInt.from_bytes = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_bytes(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_bytes(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a new UInt from j.
|
// Return a new UInt from j.
|
||||||
UInt.from_bn = function(j) {
|
UInt.from_bn = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_bn(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_bn(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return a new UInt from j.
|
// Return a new UInt from j.
|
||||||
UInt.from_number = function(j) {
|
UInt.from_number = function(j) {
|
||||||
if (j instanceof this) {
|
if (j instanceof this) {
|
||||||
return j.clone();
|
return j.clone();
|
||||||
} else {
|
|
||||||
return (new this()).parse_number(j);
|
|
||||||
}
|
}
|
||||||
|
return (new this()).parse_number(j);
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt.is_valid = function(j) {
|
UInt.is_valid = function(j) {
|
||||||
@@ -96,6 +90,10 @@ UInt.prototype.clone = function() {
|
|||||||
UInt.prototype.copyTo = function(d) {
|
UInt.prototype.copyTo = function(d) {
|
||||||
d._value = this._value;
|
d._value = this._value;
|
||||||
|
|
||||||
|
if (this._version_byte !== undefined) {
|
||||||
|
d._version_byte = this._version_byte;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof d._update === 'function') {
|
if (typeof d._update === 'function') {
|
||||||
d._update();
|
d._update();
|
||||||
}
|
}
|
||||||
@@ -104,15 +102,15 @@ UInt.prototype.copyTo = function(d) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
UInt.prototype.equals = function(d) {
|
UInt.prototype.equals = function(d) {
|
||||||
return this._value instanceof BigInteger && d._value instanceof BigInteger && this._value.equals(d._value);
|
return this.is_valid() && d.is_valid() && this._value.equals(d._value);
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt.prototype.is_valid = function() {
|
UInt.prototype.is_valid = function() {
|
||||||
return this._value instanceof BigInteger;
|
return this._value instanceof sjcl.bn;
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt.prototype.is_zero = function() {
|
UInt.prototype.is_zero = function() {
|
||||||
return this._value.equals(BigInteger.ZERO);
|
return this.is_valid() && this._value.equals(new sjcl.bn(0));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,6 +122,8 @@ UInt.prototype.is_zero = function() {
|
|||||||
*
|
*
|
||||||
* The reason for keeping this mechanism in this class is so every subclass can
|
* The reason for keeping this mechanism in this class is so every subclass can
|
||||||
* call it whenever it modifies the internal state.
|
* call it whenever it modifies the internal state.
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
UInt.prototype._update = function() {
|
UInt.prototype._update = function() {
|
||||||
// Nothing to do by default. Subclasses will override this.
|
// Nothing to do by default. Subclasses will override this.
|
||||||
@@ -136,30 +136,32 @@ UInt.prototype.parse_generic = function(j) {
|
|||||||
j = config.accounts[j].account;
|
j = config.accounts[j].account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (j) {
|
switch (j) {
|
||||||
case undefined:
|
case undefined:
|
||||||
case '0':
|
case '0':
|
||||||
case this.constructor.STR_ZERO:
|
case this.constructor.STR_ZERO:
|
||||||
case this.constructor.ACCOUNT_ZERO:
|
case this.constructor.ACCOUNT_ZERO:
|
||||||
case this.constructor.HEX_ZERO:
|
case this.constructor.HEX_ZERO:
|
||||||
this._value = BigInteger.valueOf();
|
this._value = new sjcl.bn(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '1':
|
case '1':
|
||||||
case this.constructor.STR_ONE:
|
case this.constructor.STR_ONE:
|
||||||
case this.constructor.ACCOUNT_ONE:
|
case this.constructor.ACCOUNT_ONE:
|
||||||
case this.constructor.HEX_ONE:
|
case this.constructor.HEX_ONE:
|
||||||
this._value = new BigInteger([1]);
|
this._value = new sjcl.bn(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (typeof j !== 'string') {
|
if (typeof j !== 'string') {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
} else if (this.constructor.width === j.length) {
|
} else if (this.constructor.width === j.length) {
|
||||||
this._value = new BigInteger(utils.stringToArray(j), 256);
|
var hex = utils.arrayToHex(utils.stringToArray(j));
|
||||||
|
this._value = new sjcl.bn(hex, 16);
|
||||||
} else if ((this.constructor.width * 2) === j.length) {
|
} else if ((this.constructor.width * 2) === j.length) {
|
||||||
// XXX Check char set!
|
// XXX Check char set!
|
||||||
this._value = new BigInteger(j, 16);
|
this._value = new sjcl.bn(j, 16);
|
||||||
} else {
|
} else {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
}
|
}
|
||||||
@@ -172,7 +174,7 @@ UInt.prototype.parse_generic = function(j) {
|
|||||||
|
|
||||||
UInt.prototype.parse_hex = function(j) {
|
UInt.prototype.parse_hex = function(j) {
|
||||||
if (typeof j === 'string' && j.length === (this.constructor.width * 2)) {
|
if (typeof j === 'string' && j.length === (this.constructor.width * 2)) {
|
||||||
this._value = new BigInteger(j, 16);
|
this._value = new sjcl.bn(j, 16);
|
||||||
} else {
|
} else {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
}
|
}
|
||||||
@@ -186,8 +188,9 @@ UInt.prototype.parse_bits = function(j) {
|
|||||||
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
|
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
} else {
|
} else {
|
||||||
var bytes = sjcl.codec.bytes.fromBits(j);
|
this._value = sjcl.bn.fromBits(j);
|
||||||
this.parse_bytes(bytes);
|
// var bytes = sjcl.codec.bytes.fromBits(j);
|
||||||
|
// this.parse_bytes(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._update();
|
this._update();
|
||||||
@@ -200,7 +203,8 @@ UInt.prototype.parse_bytes = function(j) {
|
|||||||
if (!Array.isArray(j) || j.length !== this.constructor.width) {
|
if (!Array.isArray(j) || j.length !== this.constructor.width) {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
} else {
|
} else {
|
||||||
this._value = new BigInteger([0].concat(j), 256);
|
var bits = sjcl.codec.bytes.toBits(j);
|
||||||
|
this._value = sjcl.bn.fromBits(bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._update();
|
this._update();
|
||||||
@@ -212,9 +216,9 @@ UInt.prototype.parse_bytes = function(j) {
|
|||||||
UInt.prototype.parse_json = UInt.prototype.parse_hex;
|
UInt.prototype.parse_json = UInt.prototype.parse_hex;
|
||||||
|
|
||||||
UInt.prototype.parse_bn = function(j) {
|
UInt.prototype.parse_bn = function(j) {
|
||||||
if ((j instanceof sjcl.bn) && j.bitLength() <= this.constructor.width * 8) {
|
if ((j instanceof sjcl.bn) &&
|
||||||
var bytes = sjcl.codec.bytes.fromBits(j.toBits());
|
j.bitLength() <= this.constructor.width * 8) {
|
||||||
this._value = new BigInteger(bytes, 256);
|
this._value = new sjcl.bn(j);
|
||||||
} else {
|
} else {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
}
|
}
|
||||||
@@ -228,7 +232,7 @@ UInt.prototype.parse_number = function(j) {
|
|||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
|
|
||||||
if (typeof j === 'number' && isFinite(j) && j >= 0) {
|
if (typeof j === 'number' && isFinite(j) && j >= 0) {
|
||||||
this._value = new BigInteger(String(j));
|
this._value = new sjcl.bn(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._update();
|
this._update();
|
||||||
@@ -238,51 +242,31 @@ UInt.prototype.parse_number = function(j) {
|
|||||||
|
|
||||||
// Convert from internal form.
|
// Convert from internal form.
|
||||||
UInt.prototype.to_bytes = function() {
|
UInt.prototype.to_bytes = function() {
|
||||||
if (!(this._value instanceof BigInteger)) {
|
if (!this.is_valid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return sjcl.codec.bytes.fromBits(this.to_bits());
|
||||||
var bytes = this._value.toByteArray();
|
|
||||||
|
|
||||||
bytes = bytes.map(function(b) {
|
|
||||||
return (b + 256) % 256;
|
|
||||||
});
|
|
||||||
|
|
||||||
var target = this.constructor.width;
|
|
||||||
|
|
||||||
// XXX Make sure only trim off leading zeros.
|
|
||||||
bytes = bytes.slice(-target);
|
|
||||||
|
|
||||||
while (bytes.length < target) {
|
|
||||||
bytes.unshift(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt.prototype.to_hex = function() {
|
UInt.prototype.to_hex = function() {
|
||||||
if (!(this._value instanceof BigInteger)) {
|
if (!this.is_valid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return sjcl.codec.hex.fromBits(this.to_bits()).toUpperCase();
|
||||||
var bytes = this.to_bytes();
|
|
||||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(bytes)).toUpperCase();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt.prototype.to_json = UInt.prototype.to_hex;
|
UInt.prototype.to_json = UInt.prototype.to_hex;
|
||||||
|
|
||||||
UInt.prototype.to_bits = function() {
|
UInt.prototype.to_bits = function() {
|
||||||
if (!(this._value instanceof BigInteger)) {
|
if (!this.is_valid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bytes = this.to_bytes();
|
return this._value.toBits(this.constructor.width * 8);
|
||||||
|
|
||||||
return sjcl.codec.bytes.toBits(bytes);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt.prototype.to_bn = function() {
|
UInt.prototype.to_bn = function() {
|
||||||
if (!(this._value instanceof BigInteger)) {
|
if (!this.is_valid()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
var UInt = require('./uint').UInt;
|
var UInt = require('./uint').UInt;
|
||||||
@@ -7,7 +9,6 @@ var UInt = require('./uint').UInt;
|
|||||||
//
|
//
|
||||||
|
|
||||||
var UInt128 = extend(function() {
|
var UInt128 = extend(function() {
|
||||||
// Internal form: NaN or BigInteger
|
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
}, UInt);
|
}, UInt);
|
||||||
|
|
||||||
@@ -17,7 +18,8 @@ UInt128.prototype.constructor = UInt128;
|
|||||||
|
|
||||||
var HEX_ZERO = UInt128.HEX_ZERO = '00000000000000000000000000000000';
|
var HEX_ZERO = UInt128.HEX_ZERO = '00000000000000000000000000000000';
|
||||||
var HEX_ONE = UInt128.HEX_ONE = '00000000000000000000000000000000';
|
var HEX_ONE = UInt128.HEX_ONE = '00000000000000000000000000000000';
|
||||||
var STR_ZERO = UInt128.STR_ZERO = utils.hexToString(HEX_ZERO);
|
|
||||||
var STR_ONE = UInt128.STR_ONE = utils.hexToString(HEX_ONE);
|
UInt128.STR_ZERO = utils.hexToString(HEX_ZERO);
|
||||||
|
UInt128.STR_ONE = utils.hexToString(HEX_ONE);
|
||||||
|
|
||||||
exports.UInt128 = UInt128;
|
exports.UInt128 = UInt128;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var config = require('./config');
|
var config = require('./config');
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
|
|
||||||
var BigInteger = utils.jsbn.BigInteger;
|
|
||||||
|
|
||||||
var UInt = require('./uint').UInt;
|
var UInt = require('./uint').UInt;
|
||||||
var Base = require('./base').Base;
|
var Base = require('./base').Base;
|
||||||
|
|
||||||
@@ -12,9 +12,8 @@ var Base = require('./base').Base;
|
|||||||
//
|
//
|
||||||
|
|
||||||
var UInt160 = extend(function() {
|
var UInt160 = extend(function() {
|
||||||
// Internal form: NaN or BigInteger
|
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
this._version_byte = void(0);
|
this._version_byte = undefined;
|
||||||
this._update();
|
this._update();
|
||||||
}, UInt);
|
}, UInt);
|
||||||
|
|
||||||
@@ -22,12 +21,13 @@ UInt160.width = 20;
|
|||||||
UInt160.prototype = extend({}, UInt.prototype);
|
UInt160.prototype = extend({}, UInt.prototype);
|
||||||
UInt160.prototype.constructor = UInt160;
|
UInt160.prototype.constructor = UInt160;
|
||||||
|
|
||||||
var ACCOUNT_ZERO = UInt160.ACCOUNT_ZERO = 'rrrrrrrrrrrrrrrrrrrrrhoLvTp';
|
|
||||||
var ACCOUNT_ONE = UInt160.ACCOUNT_ONE = 'rrrrrrrrrrrrrrrrrrrrBZbvji';
|
|
||||||
var HEX_ZERO = UInt160.HEX_ZERO = '0000000000000000000000000000000000000000';
|
var HEX_ZERO = UInt160.HEX_ZERO = '0000000000000000000000000000000000000000';
|
||||||
var HEX_ONE = UInt160.HEX_ONE = '0000000000000000000000000000000000000001';
|
var HEX_ONE = UInt160.HEX_ONE = '0000000000000000000000000000000000000001';
|
||||||
var STR_ZERO = UInt160.STR_ZERO = utils.hexToString(HEX_ZERO);
|
|
||||||
var STR_ONE = UInt160.STR_ONE = utils.hexToString(HEX_ONE);
|
UInt160.ACCOUNT_ZERO = 'rrrrrrrrrrrrrrrrrrrrrhoLvTp';
|
||||||
|
UInt160.ACCOUNT_ONE = 'rrrrrrrrrrrrrrrrrrrrBZbvji';
|
||||||
|
UInt160.STR_ZERO = utils.hexToString(HEX_ZERO);
|
||||||
|
UInt160.STR_ONE = utils.hexToString(HEX_ONE);
|
||||||
|
|
||||||
UInt160.prototype.set_version = function(j) {
|
UInt160.prototype.set_version = function(j) {
|
||||||
this._version_byte = j;
|
this._version_byte = j;
|
||||||
@@ -49,7 +49,7 @@ UInt160.prototype.parse_json = function(j) {
|
|||||||
// Allow raw numbers - DEPRECATED
|
// Allow raw numbers - DEPRECATED
|
||||||
// This is used mostly by the test suite and is supported
|
// This is used mostly by the test suite and is supported
|
||||||
// as a legacy feature only. DO NOT RELY ON THIS BEHAVIOR.
|
// as a legacy feature only. DO NOT RELY ON THIS BEHAVIOR.
|
||||||
this._value = new BigInteger(String(j));
|
this.parse_number(j);
|
||||||
this._version_byte = Base.VER_ACCOUNT_ID;
|
this._version_byte = Base.VER_ACCOUNT_ID;
|
||||||
} else if (typeof j !== 'string') {
|
} else if (typeof j !== 'string') {
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
@@ -83,7 +83,7 @@ UInt160.prototype.parse_generic = function(j) {
|
|||||||
UInt160.prototype.to_json = function(opts) {
|
UInt160.prototype.to_json = function(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
|
||||||
if (this._value instanceof BigInteger) {
|
if (this.is_valid()) {
|
||||||
// If this value has a type, return a Base58 encoded string.
|
// If this value has a type, return a Base58 encoded string.
|
||||||
if (typeof this._version_byte === 'number') {
|
if (typeof this._version_byte === 'number') {
|
||||||
var output = Base.encode_check(this._version_byte, this.to_bytes());
|
var output = Base.encode_check(this._version_byte, this.to_bytes());
|
||||||
@@ -93,9 +93,8 @@ UInt160.prototype.to_json = function(opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
} else {
|
|
||||||
return this.to_hex();
|
|
||||||
}
|
}
|
||||||
|
return this.to_hex();
|
||||||
}
|
}
|
||||||
return NaN;
|
return NaN;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
var utils = require('./utils');
|
var utils = require('./utils');
|
||||||
var extend = require('extend');
|
var extend = require('extend');
|
||||||
var UInt = require('./uint').UInt;
|
var UInt = require('./uint').UInt;
|
||||||
@@ -7,7 +9,6 @@ var UInt = require('./uint').UInt;
|
|||||||
//
|
//
|
||||||
|
|
||||||
var UInt256 = extend(function() {
|
var UInt256 = extend(function() {
|
||||||
// Internal form: NaN or BigInteger
|
|
||||||
this._value = NaN;
|
this._value = NaN;
|
||||||
}, UInt);
|
}, UInt);
|
||||||
|
|
||||||
@@ -15,9 +16,13 @@ UInt256.width = 32;
|
|||||||
UInt256.prototype = extend({}, UInt.prototype);
|
UInt256.prototype = extend({}, UInt.prototype);
|
||||||
UInt256.prototype.constructor = UInt256;
|
UInt256.prototype.constructor = UInt256;
|
||||||
|
|
||||||
var HEX_ZERO = UInt256.HEX_ZERO = '00000000000000000000000000000000' + '00000000000000000000000000000000';
|
var HEX_ZERO = UInt256.HEX_ZERO = '00000000000000000000000000000000' +
|
||||||
var HEX_ONE = UInt256.HEX_ONE = '00000000000000000000000000000000' + '00000000000000000000000000000001';
|
'00000000000000000000000000000000';
|
||||||
var STR_ZERO = UInt256.STR_ZERO = utils.hexToString(HEX_ZERO);
|
|
||||||
var STR_ONE = UInt256.STR_ONE = utils.hexToString(HEX_ONE);
|
var HEX_ONE = UInt256.HEX_ONE = '00000000000000000000000000000000' +
|
||||||
|
'00000000000000000000000000000001';
|
||||||
|
|
||||||
|
UInt256.STR_ZERO = utils.hexToString(HEX_ZERO);
|
||||||
|
UInt256.STR_ONE = utils.hexToString(HEX_ONE);
|
||||||
|
|
||||||
exports.UInt256 = UInt256;
|
exports.UInt256 = UInt256;
|
||||||
|
|||||||
@@ -1,24 +1,22 @@
|
|||||||
function filterErr(code, done) {
|
'use strict';
|
||||||
return function(e) {
|
|
||||||
done(e.code !== code ? e : void(0));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function throwErr(done) {
|
function getMantissaDecimalString(bignum) {
|
||||||
return function(e) {
|
var mantissa = bignum.toPrecision(16)
|
||||||
if (e) {
|
.replace(/\./, '') // remove decimal point
|
||||||
throw e;
|
.replace(/e.*/, '') // remove scientific notation
|
||||||
|
.replace(/^0*/, ''); // remove leading zeroes
|
||||||
|
while (mantissa.length < 16) {
|
||||||
|
mantissa += '0'; // add trailing zeroes until length is 16
|
||||||
|
}
|
||||||
|
return mantissa;
|
||||||
}
|
}
|
||||||
done();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function trace(comment, func) {
|
function trace(comment, func) {
|
||||||
return function() {
|
return function() {
|
||||||
console.log('%s: %s', trace, arguments.toString);
|
console.log('%s: %s', trace, arguments.toString);
|
||||||
func(arguments);
|
func(arguments);
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
function arraySet(count, value) {
|
function arraySet(count, value) {
|
||||||
var a = new Array(count);
|
var a = new Array(count);
|
||||||
@@ -28,7 +26,7 @@ function arraySet(count, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
};
|
}
|
||||||
|
|
||||||
function hexToString(h) {
|
function hexToString(h) {
|
||||||
var a = [];
|
var a = [];
|
||||||
@@ -44,7 +42,7 @@ function hexToString(h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return a.join('');
|
return a.join('');
|
||||||
};
|
}
|
||||||
|
|
||||||
function stringToHex(s) {
|
function stringToHex(s) {
|
||||||
var result = '';
|
var result = '';
|
||||||
@@ -53,7 +51,7 @@ function stringToHex(s) {
|
|||||||
result += b < 16 ? '0' + b.toString(16) : b.toString(16);
|
result += b < 16 ? '0' + b.toString(16) : b.toString(16);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
}
|
||||||
|
|
||||||
function stringToArray(s) {
|
function stringToArray(s) {
|
||||||
var a = new Array(s.length);
|
var a = new Array(s.length);
|
||||||
@@ -63,11 +61,18 @@ function stringToArray(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
};
|
}
|
||||||
|
|
||||||
function hexToArray(h) {
|
function hexToArray(h) {
|
||||||
return stringToArray(hexToString(h));
|
return stringToArray(hexToString(h));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function arrayToHex(a) {
|
||||||
|
return a.map(function(byteValue) {
|
||||||
|
var hex = byteValue.toString(16);
|
||||||
|
return hex.length > 1 ? hex : '0' + hex;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
function chunkString(str, n, leftAlign) {
|
function chunkString(str, n, leftAlign) {
|
||||||
var ret = [];
|
var ret = [];
|
||||||
@@ -85,16 +90,17 @@ function chunkString(str, n, leftAlign) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
};
|
}
|
||||||
|
|
||||||
function assert(assertion, msg) {
|
function assert(assertion, msg) {
|
||||||
if (!assertion) {
|
if (!assertion) {
|
||||||
throw new Error('Assertion failed' + (msg ? ': ' + msg : '.'));
|
throw new Error('Assertion failed' + (msg ? ': ' + msg : '.'));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return unique values in array.
|
* @param {Array} arr (values)
|
||||||
|
* @return {Array} unique values (for string representation of value) in `arr`
|
||||||
*/
|
*/
|
||||||
function arrayUnique(arr) {
|
function arrayUnique(arr) {
|
||||||
var u = {}, a = [];
|
var u = {}, a = [];
|
||||||
@@ -109,29 +115,28 @@ function arrayUnique(arr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a ripple epoch to a JavaScript timestamp.
|
* @param {Number} rpepoch (seconds since 1/1/2000 GMT)
|
||||||
|
* @return {Number} ms since unix epoch
|
||||||
*
|
*
|
||||||
* JavaScript timestamps are unix epoch in milliseconds.
|
|
||||||
*/
|
*/
|
||||||
function toTimestamp(rpepoch) {
|
function toTimestamp(rpepoch) {
|
||||||
return (rpepoch + 0x386D4380) * 1000;
|
return (rpepoch + 0x386D4380) * 1000;
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a JavaScript timestamp or Date to a Ripple epoch.
|
|
||||||
*
|
|
||||||
* JavaScript timestamps are unix epoch in milliseconds.
|
|
||||||
*/
|
|
||||||
function fromTimestamp(rpepoch) {
|
|
||||||
if (rpepoch instanceof Date) {
|
|
||||||
rpepoch = rpepoch.getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.round(rpepoch / 1000) - 0x386D4380;
|
/**
|
||||||
};
|
* @param {Number|Date} timestamp (ms since unix epoch)
|
||||||
|
* @return {Number} seconds since ripple epoch ( 1/1/2000 GMT)
|
||||||
|
*/
|
||||||
|
function fromTimestamp(timestamp) {
|
||||||
|
if (timestamp instanceof Date) {
|
||||||
|
timestamp = timestamp.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.round(timestamp / 1000) - 0x386D4380;
|
||||||
|
}
|
||||||
|
|
||||||
exports.time = {
|
exports.time = {
|
||||||
fromRipple: toTimestamp,
|
fromRipple: toTimestamp,
|
||||||
@@ -144,15 +149,16 @@ exports.hexToString = hexToString;
|
|||||||
exports.hexToArray = hexToArray;
|
exports.hexToArray = hexToArray;
|
||||||
exports.stringToArray = stringToArray;
|
exports.stringToArray = stringToArray;
|
||||||
exports.stringToHex = stringToHex;
|
exports.stringToHex = stringToHex;
|
||||||
|
exports.arrayToHex = arrayToHex;
|
||||||
exports.chunkString = chunkString;
|
exports.chunkString = chunkString;
|
||||||
exports.assert = assert;
|
exports.assert = assert;
|
||||||
exports.arrayUnique = arrayUnique;
|
exports.arrayUnique = arrayUnique;
|
||||||
exports.toTimestamp = toTimestamp;
|
exports.toTimestamp = toTimestamp;
|
||||||
exports.fromTimestamp = fromTimestamp;
|
exports.fromTimestamp = fromTimestamp;
|
||||||
|
exports.getMantissaDecimalString = getMantissaDecimalString;
|
||||||
|
|
||||||
// Going up three levels is needed to escape the src-cov folder used for the
|
// Going up three levels is needed to escape the src-cov folder used for the
|
||||||
// test coverage stuff.
|
// test coverage stuff.
|
||||||
exports.sjcl = require('../../../build/sjcl');
|
exports.sjcl = require('../../../build/sjcl');
|
||||||
exports.jsbn = require('../../../src/js/jsbn/jsbn');
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
// vim:sw=2:sts=2:ts=8:et
|
||||||
|
|||||||
@@ -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 assert = require('assert');
|
||||||
var Account = require('../src/js/ripple/account').Account;
|
var Account = require('ripple-lib').Account;
|
||||||
|
|
||||||
describe('Account', function(){
|
describe('Account', function(){
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
|
/* eslint-disable max-len */
|
||||||
|
'use strict';
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var Amount = require('ripple-lib').Amount;
|
||||||
var BigInteger = require('../src/js/jsbn/jsbn').BigInteger;
|
var UInt160 = require('ripple-lib').UInt160;
|
||||||
var Amount = utils.load_module('amount').Amount;
|
var load_config = require('ripple-lib').config.load;
|
||||||
var UInt160 = utils.load_module('uint160').UInt160;
|
var config = require('./config-example');
|
||||||
var config = utils.get_config();
|
|
||||||
|
load_config(config);
|
||||||
|
|
||||||
|
|
||||||
describe('Amount', function() {
|
describe('Amount', function() {
|
||||||
describe('Negatives', function() {
|
describe('Negatives', function() {
|
||||||
@@ -24,209 +28,224 @@ describe('Amount', function() {
|
|||||||
// also tested extensively in other cases
|
// also tested extensively in other cases
|
||||||
describe('to_human', function() {
|
describe('to_human', function() {
|
||||||
it('12345.6789 XAU', function() {
|
it('12345.6789 XAU', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 XAU").to_human(), '12,345.6789');
|
assert.strictEqual(Amount.from_human('12345.6789 XAU').to_human(), '12,345.6789');
|
||||||
});
|
});
|
||||||
it('12345.678901234 XAU', function() {
|
it('12345.678901234 XAU', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human(), '12,345.678901234');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human(), '12,345.678901234');
|
||||||
});
|
});
|
||||||
it('to human, precision -1, should be ignored, precision needs to be >= 0', function() {
|
it('to human, precision -1, should be ignored, precision needs to be >= 0', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:-1}), '12,346');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: -1}), '12,346');
|
||||||
});
|
});
|
||||||
it('to human, precision 0', function() {
|
it('to human, precision 0', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:0}), '12,346');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 0}), '12,346');
|
||||||
});
|
});
|
||||||
it('to human, precision 1', function() {
|
it('to human, precision 1', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:1}), '12,345.7');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 1}), '12,345.7');
|
||||||
});
|
});
|
||||||
it('to human, precision 2', function() {
|
it('to human, precision 2', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:2}), '12,345.68');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 2}), '12,345.68');
|
||||||
});
|
});
|
||||||
it('to human, precision 3', function() {
|
it('to human, precision 3', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:3}), '12,345.679');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 3}), '12,345.679');
|
||||||
});
|
});
|
||||||
it('to human, precision 4', function() {
|
it('to human, precision 4', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:4}), '12,345.6789');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 4}), '12,345.6789');
|
||||||
});
|
});
|
||||||
it('to human, precision 5', function() {
|
it('to human, precision 5', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.678901234 XAU").to_human({precision:5}), '12,345.67890');
|
assert.strictEqual(Amount.from_human('12345.678901234 XAU').to_human({precision: 5}), '12,345.67890');
|
||||||
});
|
});
|
||||||
it('to human, precision -1, should be ignored, precision needs to be >= 0', function() {
|
it('to human, precision -1, should be ignored, precision needs to be >= 0', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:-1}), '0');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: -1}), '0');
|
||||||
});
|
});
|
||||||
it('to human, precision 0', function() {
|
it('to human, precision 0', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:0}), '0');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 0}), '0');
|
||||||
});
|
});
|
||||||
it('to human, precision 1', function() {
|
it('to human, precision 1', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:1}), '0.0');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 1}), '0.0');
|
||||||
});
|
});
|
||||||
it('to human, precision 2', function() {
|
it('to human, precision 2', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:2}), '0.00');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 2}), '0.00');
|
||||||
});
|
});
|
||||||
it('to human, precision 5', function() {
|
it('to human, precision 5', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:5}), '0.00012');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 5}), '0.00012');
|
||||||
});
|
});
|
||||||
it('to human, precision 6', function() {
|
it('to human, precision 6', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:6}), '0.000123');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 6}), '0.000123');
|
||||||
});
|
});
|
||||||
it('to human, precision 16', function() {
|
it('to human, precision 16', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:16}), '0.00012345');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 16}), '0.00012345');
|
||||||
});
|
});
|
||||||
it('to human, precision 16, min_precision 16', function() {
|
it('to human, precision 16, min_precision 16', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:16, min_precision:16}), '0.0001234500000000');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 16, min_precision: 16}), '0.0001234500000000');
|
||||||
});
|
});
|
||||||
it('to human, precision 16, min_precision 12', function() {
|
it('to human, precision 16, min_precision 12', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.00012345 XAU").to_human({precision:16, min_precision:12}), '0.000123450000');
|
assert.strictEqual(Amount.from_human('0.00012345 XAU').to_human({precision: 16, min_precision: 12}), '0.000123450000');
|
||||||
});
|
});
|
||||||
it('to human, precision 0, first decimal 4', function() {
|
it('to human, precision 0, first decimal 4', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.4 XAU").to_human({precision:0}), '0');
|
assert.strictEqual(Amount.from_human('0.4 XAU').to_human({precision: 0}), '0');
|
||||||
});
|
});
|
||||||
it('to human, precision 0, first decimal 5', function() {
|
it('to human, precision 0, first decimal 5', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.5 XAU").to_human({precision:0}), '1');
|
assert.strictEqual(Amount.from_human('0.5 XAU').to_human({precision: 0}), '1');
|
||||||
});
|
});
|
||||||
it('to human, precision 0, first decimal 8', function() {
|
it('to human, precision 0, first decimal 8', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.8 XAU").to_human({precision:0}), '1');
|
assert.strictEqual(Amount.from_human('0.8 XAU').to_human({precision: 0}), '1');
|
||||||
});
|
});
|
||||||
it('to human, precision 0, precision 16', function() {
|
it('to human, precision 0, precision 16', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision:16}), '0');
|
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 16}), '0');
|
||||||
});
|
});
|
||||||
it('to human, precision 0, precision 8, min_precision 16', function() {
|
it('to human, precision 0, precision 8, min_precision 16', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision:8, min_precision:16}), '0.0000000000000000');
|
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 8, min_precision: 16}), '0.0000000000000000');
|
||||||
});
|
});
|
||||||
it('to human, precision 0, first decimal 8', function() {
|
it('to human, precision 0, first decimal 8', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.8 XAU").to_human({precision:0}), '1');
|
assert.strictEqual(Amount.from_human('0.8 XAU').to_human({precision: 0}), '1');
|
||||||
});
|
});
|
||||||
it('to human, precision 6, min_precision 6, max_sig_digits 20', function() {
|
it('to human, precision 6, min_precision 6, max_sig_digits 20', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision: 6, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 6, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
||||||
});
|
});
|
||||||
it('to human, precision 16, min_precision 6, max_sig_digits 20', function() {
|
it('to human, precision 16, min_precision 6, max_sig_digits 20', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.0 XAU").to_human({precision: 16, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
assert.strictEqual(Amount.from_human('0.0 XAU').to_human({precision: 16, min_precision: 6, max_sig_digits: 20}), '0.000000');
|
||||||
});
|
});
|
||||||
it('to human rounding edge case, precision 2, 1', function() {
|
it('to human rounding edge case, precision 2, 1', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:1}), '1.0');
|
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 1}), '1.0');
|
||||||
});
|
});
|
||||||
it('to human rounding edge case, precision 2, 2', function() {
|
it('to human rounding edge case, precision 2, 2', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:2}), '0.99');
|
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 2}), '0.99');
|
||||||
});
|
});
|
||||||
it('to human rounding edge case, precision 2, 3', function() {
|
it('to human rounding edge case, precision 2, 3', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:3}), '0.99');
|
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 3}), '0.99');
|
||||||
});
|
});
|
||||||
it('to human rounding edge case, precision 2, 3 min precision 3', function() {
|
it('to human rounding edge case, precision 2, 3 min precision 3', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.99 XAU").to_human({precision:3, min_precision:3}), '0.990');
|
assert.strictEqual(Amount.from_human('0.99 XAU').to_human({precision: 3, min_precision: 3}), '0.990');
|
||||||
});
|
});
|
||||||
it('to human rounding edge case, precision 3, 2', function() {
|
it('to human rounding edge case, precision 3, 2', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.999 XAU").to_human({precision:2}), '1.00');
|
assert.strictEqual(Amount.from_human('0.999 XAU').to_human({precision: 2}), '1.00');
|
||||||
|
});
|
||||||
|
it('to human very small number', function() {
|
||||||
|
assert.strictEqual(Amount.from_json('12e-20/USD').to_human(), '0.00000000000000000012');
|
||||||
|
});
|
||||||
|
it('to human very small number with precision', function() {
|
||||||
|
assert.strictEqual(Amount.from_json('12e-20/USD').to_human({precision: 20}), '0.00000000000000000012');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('from_human', function() {
|
describe('from_human', function() {
|
||||||
|
it('empty string', function() {
|
||||||
|
assert.strictEqual(Amount.from_human('').to_text_full(), 'NaN');
|
||||||
|
});
|
||||||
|
it('missing value', function() {
|
||||||
|
assert.strictEqual(Amount.from_human('USD').to_text_full(), 'NaN');
|
||||||
|
});
|
||||||
it('1 XRP', function() {
|
it('1 XRP', function() {
|
||||||
assert.strictEqual(Amount.from_human("1 XRP").to_text_full(), '1/XRP');
|
assert.strictEqual(Amount.from_human('1 XRP').to_text_full(), '1/XRP');
|
||||||
});
|
});
|
||||||
it('1 XRP human', function() {
|
it('1 XRP human', function() {
|
||||||
assert.strictEqual(Amount.from_human("1 XRP").to_human_full(), '1/XRP');
|
assert.strictEqual(Amount.from_human('1 XRP').to_human_full(), '1/XRP');
|
||||||
|
});
|
||||||
|
it('1XRP human', function() {
|
||||||
|
assert.strictEqual(Amount.from_human('1XRP').to_human_full(), '1/XRP');
|
||||||
});
|
});
|
||||||
it('0.1 XRP', function() {
|
it('0.1 XRP', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.1 XRP").to_text_full(), '0.1/XRP');
|
assert.strictEqual(Amount.from_human('0.1 XRP').to_text_full(), '0.1/XRP');
|
||||||
});
|
});
|
||||||
it('0.1 XRP human', function() {
|
it('0.1 XRP human', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.1 XRP").to_human_full(), '0.1/XRP');
|
assert.strictEqual(Amount.from_human('0.1 XRP').to_human_full(), '0.1/XRP');
|
||||||
});
|
});
|
||||||
it('0.1 USD', function() {
|
it('0.1 USD', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.1 USD").to_text_full(), '0.1/USD/NaN');
|
assert.strictEqual(Amount.from_human('0.1 USD').to_text_full(), '0.1/USD/NaN');
|
||||||
});
|
});
|
||||||
it('0.1 USD human', function() {
|
it('0.1 USD human', function() {
|
||||||
assert.strictEqual(Amount.from_human("0.1 USD").to_human_full(), '0.1/USD/NaN');
|
assert.strictEqual(Amount.from_human('0.1 USD').to_human_full(), '0.1/USD/NaN');
|
||||||
});
|
});
|
||||||
it('10000 USD', function() {
|
it('10000 USD', function() {
|
||||||
assert.strictEqual(Amount.from_human("10000 USD").to_text_full(), '10000/USD/NaN');
|
assert.strictEqual(Amount.from_human('10000 USD').to_text_full(), '10000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('10000 USD human', function() {
|
it('10000 USD human', function() {
|
||||||
assert.strictEqual(Amount.from_human("10000 USD").to_human_full(), '10,000/USD/NaN');
|
assert.strictEqual(Amount.from_human('10000 USD').to_human_full(), '10,000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('USD 10000', function() {
|
it('USD 10000', function() {
|
||||||
assert.strictEqual(Amount.from_human("USD 10000").to_text_full(), '10000/USD/NaN');
|
assert.strictEqual(Amount.from_human('USD 10000').to_text_full(), '10000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('USD 10000 human', function() {
|
it('USD 10000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("USD 10000").to_human_full(), '10,000/USD/NaN');
|
assert.strictEqual(Amount.from_human('USD 10000').to_human_full(), '10,000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 XAU', function() {
|
it('12345.6789 XAU', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 XAU").to_text_full(), '12345.6789/XAU/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 XAU').to_text_full(), '12345.6789/XAU/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 XAU human', function() {
|
it('12345.6789 XAU human', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 XAU").to_human_full(), '12,345.6789/XAU/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 XAU').to_human_full(), '12,345.6789/XAU/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() {
|
it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_text_full(), '12345.6789/XAU (-0.5%pa)/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000').to_text_full(), '12345.6789/XAU (-0.5%pa)/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000 human', function() {
|
it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_human_full(), '12,345.6789/XAU (-0.5%pa)/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000').to_human_full(), '12,345.6789/XAU (-0.5%pa)/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 0000000000000000000000005553440000000000', function() {
|
it('12345.6789 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 0000000000000000000000005553440000000000").to_text_full(), '12345.6789/USD/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 0000000000000000000000005553440000000000').to_text_full(), '12345.6789/USD/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 0000000000000000000000005553440000000000 human', function() {
|
it('12345.6789 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 0000000000000000000000005553440000000000").to_human_full(), '12,345.6789/USD/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 0000000000000000000000005553440000000000').to_human_full(), '12,345.6789/USD/NaN');
|
||||||
});
|
});
|
||||||
it('10 0000000000000000000000005553440000000000', function() {
|
it('10 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("10 0000000000000000000000005553440000000000").to_text_full(), '10/USD/NaN');
|
assert.strictEqual(Amount.from_human('10 0000000000000000000000005553440000000000').to_text_full(), '10/USD/NaN');
|
||||||
});
|
});
|
||||||
it('10 0000000000000000000000005553440000000000 human', function() {
|
it('10 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("10 0000000000000000000000005553440000000000").to_human_full(), '10/USD/NaN');
|
assert.strictEqual(Amount.from_human('10 0000000000000000000000005553440000000000').to_human_full(), '10/USD/NaN');
|
||||||
});
|
});
|
||||||
it('100 0000000000000000000000005553440000000000', function() {
|
it('100 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("100 0000000000000000000000005553440000000000").to_text_full(), '100/USD/NaN');
|
assert.strictEqual(Amount.from_human('100 0000000000000000000000005553440000000000').to_text_full(), '100/USD/NaN');
|
||||||
});
|
});
|
||||||
it('100 0000000000000000000000005553440000000000 human', function() {
|
it('100 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("100 0000000000000000000000005553440000000000").to_human_full(), '100/USD/NaN');
|
assert.strictEqual(Amount.from_human('100 0000000000000000000000005553440000000000').to_human_full(), '100/USD/NaN');
|
||||||
});
|
});
|
||||||
it('1000 0000000000000000000000005553440000000000', function() {
|
it('1000 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("1000 0000000000000000000000005553440000000000").to_text_full(), '1000/USD/NaN');
|
assert.strictEqual(Amount.from_human('1000 0000000000000000000000005553440000000000').to_text_full(), '1000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('1000 0000000000000000000000005553440000000000 human', function() {
|
it('1000 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("1000 0000000000000000000000005553440000000000").to_human_full(), '1,000/USD/NaN');
|
assert.strictEqual(Amount.from_human('1000 0000000000000000000000005553440000000000').to_human_full(), '1,000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('-100 0000000000000000000000005553440000000000', function() {
|
it('-100 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("-100 0000000000000000000000005553440000000000").to_text_full(), '-100/USD/NaN');
|
assert.strictEqual(Amount.from_human('-100 0000000000000000000000005553440000000000').to_text_full(), '-100/USD/NaN');
|
||||||
});
|
});
|
||||||
it('-100 0000000000000000000000005553440000000000 human', function() {
|
it('-100 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("-100 0000000000000000000000005553440000000000").to_human_full(), '-100/USD/NaN');
|
assert.strictEqual(Amount.from_human('-100 0000000000000000000000005553440000000000').to_human_full(), '-100/USD/NaN');
|
||||||
});
|
});
|
||||||
it('-1000 0000000000000000000000005553440000000000', function() {
|
it('-1000 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("-1000 0000000000000000000000005553440000000000").to_text_full(), '-1000/USD/NaN');
|
assert.strictEqual(Amount.from_human('-1000 0000000000000000000000005553440000000000').to_text_full(), '-1000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('-1000 0000000000000000000000005553440000000000 human', function() {
|
it('-1000 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("-1000 0000000000000000000000005553440000000000").to_human_full(), '-1,000/USD/NaN');
|
assert.strictEqual(Amount.from_human('-1000 0000000000000000000000005553440000000000').to_human_full(), '-1,000/USD/NaN');
|
||||||
});
|
});
|
||||||
it('-1000.001 0000000000000000000000005553440000000000', function() {
|
it('-1000.001 0000000000000000000000005553440000000000', function() {
|
||||||
assert.strictEqual(Amount.from_human("-1000.001 0000000000000000000000005553440000000000").to_text_full(), '-1000.001/USD/NaN');
|
assert.strictEqual(Amount.from_human('-1000.001 0000000000000000000000005553440000000000').to_text_full(), '-1000.001/USD/NaN');
|
||||||
});
|
});
|
||||||
it('-1000.001 0000000000000000000000005553440000000000 human', function() {
|
it('-1000.001 0000000000000000000000005553440000000000 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("-1000.001 0000000000000000000000005553440000000000").to_human_full(), '-1,000.001/USD/NaN');
|
assert.strictEqual(Amount.from_human('-1000.001 0000000000000000000000005553440000000000').to_human_full(), '-1,000.001/USD/NaN');
|
||||||
});
|
});
|
||||||
it('XAU 12345.6789', function() {
|
it('XAU 12345.6789', function() {
|
||||||
assert.strictEqual(Amount.from_human("XAU 12345.6789").to_text_full(), '12345.6789/XAU/NaN');
|
assert.strictEqual(Amount.from_human('XAU 12345.6789').to_text_full(), '12345.6789/XAU/NaN');
|
||||||
});
|
});
|
||||||
it('XAU 12345.6789 human', function() {
|
it('XAU 12345.6789 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("XAU 12345.6789").to_human_full(), '12,345.6789/XAU/NaN');
|
assert.strictEqual(Amount.from_human('XAU 12345.6789').to_human_full(), '12,345.6789/XAU/NaN');
|
||||||
});
|
});
|
||||||
it('101 12345.6789', function() {
|
it('101 12345.6789', function() {
|
||||||
assert.strictEqual(Amount.from_human("101 12345.6789").to_text_full(), '12345.6789/101/NaN');
|
assert.strictEqual(Amount.from_human('101 12345.6789').to_text_full(), '12345.6789/101/NaN');
|
||||||
});
|
});
|
||||||
it('101 12345.6789 human', function() {
|
it('101 12345.6789 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("101 12345.6789").to_human_full(), '12,345.6789/101/NaN');
|
assert.strictEqual(Amount.from_human('101 12345.6789').to_human_full(), '12,345.6789/101/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 101', function() {
|
it('12345.6789 101', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 101").to_text_full(), '12345.6789/101/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 101').to_text_full(), '12345.6789/101/NaN');
|
||||||
});
|
});
|
||||||
it('12345.6789 101 human', function() {
|
it('12345.6789 101 human', function() {
|
||||||
assert.strictEqual(Amount.from_human("12345.6789 101").to_human_full(), '12,345.6789/101/NaN');
|
assert.strictEqual(Amount.from_human('12345.6789 101').to_human_full(), '12,345.6789/101/NaN');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('from_json', function() {
|
describe('from_json', function() {
|
||||||
it('1 XRP', function() {
|
it('1 XRP', function() {
|
||||||
assert.strictEqual(Amount.from_json("1/XRP").to_text_full(), "1/XRP/NaN");
|
assert.strictEqual(Amount.from_json('1/XRP').to_text_full(), '1/XRP/NaN');
|
||||||
});
|
});
|
||||||
it('1 XRP human', function() {
|
it('1 XRP human', function() {
|
||||||
assert.strictEqual(Amount.from_json("1/XRP").to_human_full(), "1/XRP/NaN");
|
assert.strictEqual(Amount.from_json('1/XRP').to_human_full(), '1/XRP/NaN');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('from_number', function() {
|
describe('from_number', function() {
|
||||||
@@ -278,14 +297,11 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('UInt160', function() {
|
describe('UInt160', function() {
|
||||||
it('Parse 0', function () {
|
|
||||||
assert.deepEqual(new BigInteger(), UInt160.from_generic('0')._value);
|
|
||||||
});
|
|
||||||
it('Parse 0 export', function () {
|
it('Parse 0 export', function () {
|
||||||
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json());
|
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json());
|
||||||
});
|
});
|
||||||
it('Parse 1', function () {
|
it('Parse 1', function () {
|
||||||
assert.deepEqual(new BigInteger([1]), UInt160.from_generic('1')._value);
|
assert.deepEqual(UInt160.ACCOUNT_ONE, UInt160.from_generic('1').set_version(0).to_json());
|
||||||
});
|
});
|
||||||
it('Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export', function () {
|
it('Parse rrrrrrrrrrrrrrrrrrrrrhoLvTp export', function () {
|
||||||
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json());
|
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json());
|
||||||
@@ -294,7 +310,7 @@ describe('Amount', function() {
|
|||||||
assert.strictEqual(UInt160.ACCOUNT_ONE, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrBZbvji').to_json());
|
assert.strictEqual(UInt160.ACCOUNT_ONE, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrBZbvji').to_json());
|
||||||
});
|
});
|
||||||
it('Parse mtgox export', function () {
|
it('Parse mtgox export', function () {
|
||||||
assert.strictEqual(config.accounts['mtgox'].account, UInt160.from_json('mtgox').to_json());
|
assert.strictEqual(config.accounts.mtgox.account, UInt160.from_json('mtgox').to_json());
|
||||||
});
|
});
|
||||||
it('is_valid rrrrrrrrrrrrrrrrrrrrrhoLvTp', function () {
|
it('is_valid rrrrrrrrrrrrrrrrrrrrrhoLvTp', function () {
|
||||||
assert(UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvTp'));
|
assert(UInt160.is_valid('rrrrrrrrrrrrrrrrrrrrrhoLvTp'));
|
||||||
@@ -328,9 +344,9 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
describe('Amount parsing', function() {
|
describe('Amount parsing', function() {
|
||||||
it('Parse invalid string', function() {
|
it('Parse invalid string', function() {
|
||||||
assert.strictEqual(Amount.from_json('x').to_text(), '0');
|
assert.strictEqual(Amount.from_json('x').to_text(), 'NaN');
|
||||||
assert.strictEqual(typeof Amount.from_json('x').to_text(true), 'number');
|
assert.strictEqual(typeof Amount.from_json('x').to_text(), 'string');
|
||||||
assert(isNaN(Amount.from_json('x').to_text(true)));
|
assert(isNaN(Amount.from_json('x').to_text()));
|
||||||
});
|
});
|
||||||
it('parse dem', function() {
|
it('parse dem', function() {
|
||||||
assert.strictEqual(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
assert.strictEqual(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
@@ -345,31 +361,35 @@ describe('Amount', function() {
|
|||||||
assert.strictEqual(Amount.from_json('10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
assert.strictEqual(Amount.from_json('10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
});
|
});
|
||||||
it('Parse 800/USD/mtgox', function () {
|
it('Parse 800/USD/mtgox', function () {
|
||||||
assert.strictEqual('800/USD/'+config.accounts['mtgox'].account, Amount.from_json('800/USD/mtgox').to_text_full());
|
assert.strictEqual('800/USD/' + config.accounts.mtgox.account, Amount.from_json('800/USD/mtgox').to_text_full());
|
||||||
});
|
});
|
||||||
it('Parse 800/USD/mtgox human', function () {
|
it('Parse 800/USD/mtgox human', function () {
|
||||||
assert.strictEqual('800/USD/'+config.accounts['mtgox'].account, Amount.from_json('800/USD/mtgox').to_human_full());
|
assert.strictEqual('800/USD/' + config.accounts.mtgox.account, Amount.from_json('800/USD/mtgox').to_human_full());
|
||||||
});
|
});
|
||||||
it('Parse native 0', function () {
|
it('Parse native 0', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('0').to_text_full());
|
assert.strictEqual('0/XRP', Amount.from_json('0').to_text_full());
|
||||||
});
|
});
|
||||||
it('Parse native 0.0', function () {
|
it('Parse native 0.0', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('0.0').to_text_full());
|
assert.throws(function() {
|
||||||
|
Amount.from_json('0.0');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('Parse native -0', function () {
|
it('Parse native -0', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('-0').to_text_full());
|
assert.strictEqual('0/XRP', Amount.from_json('-0').to_text_full());
|
||||||
});
|
});
|
||||||
it('Parse native -0.0', function () {
|
it('Parse native -0.0', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('-0.0').to_text_full());
|
assert.throws(function() {
|
||||||
|
Amount.from_json('-0.0');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('Parse native 1000', function () {
|
it('Parse native 1000', function () {
|
||||||
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_text_full());
|
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_text_full());
|
||||||
});
|
});
|
||||||
it('Parse native 12.3', function () {
|
it('Parse native 12300000', function () {
|
||||||
assert.strictEqual('12.3/XRP', Amount.from_json('12.3').to_text_full());
|
assert.strictEqual('12.3/XRP', Amount.from_json('12300000').to_text_full());
|
||||||
});
|
});
|
||||||
it('Parse native -12.3', function () {
|
it('Parse native -12300000', function () {
|
||||||
assert.strictEqual('-12.3/XRP', Amount.from_json('-12.3').to_text_full());
|
assert.strictEqual('-12.3/XRP', Amount.from_json('-12300000').to_text_full());
|
||||||
});
|
});
|
||||||
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||||
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
|
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
|
||||||
@@ -398,23 +418,17 @@ describe('Amount', function() {
|
|||||||
it('Parse native 0 human', function () {
|
it('Parse native 0 human', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('0').to_human_full());
|
assert.strictEqual('0/XRP', Amount.from_json('0').to_human_full());
|
||||||
});
|
});
|
||||||
it('Parse native 0.0 human', function () {
|
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('0.0').to_human_full());
|
|
||||||
});
|
|
||||||
it('Parse native -0 human', function () {
|
it('Parse native -0 human', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('-0').to_human_full());
|
assert.strictEqual('0/XRP', Amount.from_json('-0').to_human_full());
|
||||||
});
|
});
|
||||||
it('Parse native -0.0 human', function () {
|
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('-0.0').to_human_full());
|
|
||||||
});
|
|
||||||
it('Parse native 1000 human', function () {
|
it('Parse native 1000 human', function () {
|
||||||
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_human_full());
|
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_human_full());
|
||||||
});
|
});
|
||||||
it('Parse native 12.3 human', function () {
|
it('Parse native 12300000 human', function () {
|
||||||
assert.strictEqual('12.3/XRP', Amount.from_json('12.3').to_human_full());
|
assert.strictEqual('12.3/XRP', Amount.from_json('12300000').to_human_full());
|
||||||
});
|
});
|
||||||
it('Parse native -12.3 human', function () {
|
it('Parse native -12300000 human', function () {
|
||||||
assert.strictEqual('-12.3/XRP', Amount.from_json('-12.3').to_human_full());
|
assert.strictEqual('-12.3/XRP', Amount.from_json('-12300000').to_human_full());
|
||||||
});
|
});
|
||||||
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh human', function () {
|
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh human', function () {
|
||||||
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
|
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
|
||||||
@@ -443,19 +457,19 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
describe('Amount to_json', function() {
|
describe('Amount to_json', function() {
|
||||||
it('10 USD', function() {
|
it('10 USD', function() {
|
||||||
var amount = Amount.from_human("10 USD").to_json();
|
var amount = Amount.from_human('10 USD').to_json();
|
||||||
assert.strictEqual("10", amount.value);
|
assert.strictEqual('10', amount.value);
|
||||||
assert.strictEqual("USD", amount.currency);
|
assert.strictEqual('USD', amount.currency);
|
||||||
});
|
});
|
||||||
it('10 0000000000000000000000005553440000000000', function() {
|
it('10 0000000000000000000000005553440000000000', function() {
|
||||||
var amount = Amount.from_human("10 0000000000000000000000005553440000000000").to_json();
|
var amount = Amount.from_human('10 0000000000000000000000005553440000000000').to_json();
|
||||||
assert.strictEqual("10", amount.value);
|
assert.strictEqual('10', amount.value);
|
||||||
assert.strictEqual("USD", amount.currency);
|
assert.strictEqual('USD', amount.currency);
|
||||||
});
|
});
|
||||||
it('10 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() {
|
it('10 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() {
|
||||||
var amount = Amount.from_human("10 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_json();
|
var amount = Amount.from_human('10 015841551A748AD2C1F76FF6ECB0CCCD00000000').to_json();
|
||||||
assert.strictEqual("10", amount.value);
|
assert.strictEqual('10', amount.value);
|
||||||
assert.strictEqual("015841551A748AD2C1F76FF6ECB0CCCD00000000", amount.currency);
|
assert.strictEqual('015841551A748AD2C1F76FF6ECB0CCCD00000000', amount.currency);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('Amount operations', function() {
|
describe('Amount operations', function() {
|
||||||
@@ -760,7 +774,7 @@ describe('Amount', function() {
|
|||||||
assert(isNaN(Amount.from_json('x').copyTo(new Amount())._value));
|
assert(isNaN(Amount.from_json('x').copyTo(new Amount())._value));
|
||||||
});
|
});
|
||||||
it('amount.copyTo zero', function() {
|
it('amount.copyTo zero', function() {
|
||||||
assert(!(Amount.from_json(0).copyTo(new Amount())._is_negative))
|
assert(!(Amount.from_json(0).copyTo(new Amount())._is_negative));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('Amount comparisons', function() {
|
describe('Amount comparisons', function() {
|
||||||
@@ -782,7 +796,7 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
it('0 XRP == 0 XRP', function () {
|
it('0 XRP == 0 XRP', function () {
|
||||||
var a = Amount.from_json('0');
|
var a = Amount.from_json('0');
|
||||||
var b = Amount.from_json('0.0');
|
var b = Amount.from_json('0');
|
||||||
assert(a.equals(b));
|
assert(a.equals(b));
|
||||||
assert(!a.not_equals_why(b));
|
assert(!a.not_equals_why(b));
|
||||||
});
|
});
|
||||||
@@ -811,8 +825,8 @@ describe('Amount', function() {
|
|||||||
assert(!a.not_equals_why(b));
|
assert(!a.not_equals_why(b));
|
||||||
});
|
});
|
||||||
it('1.1 XRP == 1.1 XRP', function () {
|
it('1.1 XRP == 1.1 XRP', function () {
|
||||||
var a = Amount.from_json('1.1');
|
var a = Amount.from_json('1100000');
|
||||||
var b = Amount.from_json('11.0').ratio_human(10);
|
var b = Amount.from_json('11000000').ratio_human('10/XRP');
|
||||||
assert(a.equals(b));
|
assert(a.equals(b));
|
||||||
assert(!a.not_equals_why(b));
|
assert(!a.not_equals_why(b));
|
||||||
});
|
});
|
||||||
@@ -970,7 +984,7 @@ describe('Amount', function() {
|
|||||||
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_text_full(), '0.0001/XRP');
|
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_text_full(), '0.0001/XRP');
|
||||||
});
|
});
|
||||||
it('Multiply USD with XAU (dem)', function () {
|
it('Multiply USD with XAU (dem)', function () {
|
||||||
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_text_full(), '19900.00316303882/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_text_full(), '19900.00316303883/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
});
|
});
|
||||||
it('Multiply 0 XRP with 0 XRP human', function () {
|
it('Multiply 0 XRP with 0 XRP human', function () {
|
||||||
assert.strictEqual('0/XRP', Amount.from_json('0').product_human(Amount.from_json('0')).to_human_full());
|
assert.strictEqual('0/XRP', Amount.from_json('0').product_human(Amount.from_json('0')).to_human_full());
|
||||||
@@ -1042,7 +1056,7 @@ describe('Amount', function() {
|
|||||||
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_human_full(), '0.0001/XRP');
|
assert.strictEqual(Amount.from_json('10000000').product_human(Amount.from_json('10')).to_human_full(), '0.0001/XRP');
|
||||||
});
|
});
|
||||||
it('Multiply USD with XAU (dem) human', function () {
|
it('Multiply USD with XAU (dem) human', function () {
|
||||||
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_human_full(), '19,900.00316303882/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
assert.strictEqual(Amount.from_json('2000/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').product_human(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh'), {reference_date: 443845330 + 31535000}).to_human_full(), '19,900.00316303883/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1077,6 +1091,11 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('from_quality', function() {
|
describe('from_quality', function() {
|
||||||
|
it('XRP/XRP', function () {
|
||||||
|
assert.throws(function() {
|
||||||
|
Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'XRP'}).to_text_full();
|
||||||
|
});
|
||||||
|
});
|
||||||
it('BTC/XRP', function () {
|
it('BTC/XRP', function () {
|
||||||
assert.strictEqual(Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'BTC'}).to_text_full(), '44,970/XRP');
|
assert.strictEqual(Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'BTC'}).to_text_full(), '44,970/XRP');
|
||||||
});
|
});
|
||||||
@@ -1155,7 +1174,7 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
it('from_human with reference date', function() {
|
it('from_human with reference date', function() {
|
||||||
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date: 459990264});
|
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date: 459990264});
|
||||||
demAmount.set_issuer("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
demAmount.set_issuer('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
assert.strictEqual(demAmount.to_text_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
assert.strictEqual(demAmount.to_text_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
});
|
});
|
||||||
it('from_json apply interest 10 XAU human', function() {
|
it('from_json apply interest 10 XAU human', function() {
|
||||||
@@ -1173,18 +1192,18 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
it('from_human with reference date human', function() {
|
it('from_human with reference date human', function() {
|
||||||
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date: 459990264});
|
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date: 459990264});
|
||||||
demAmount.set_issuer("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
demAmount.set_issuer('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
assert.strictEqual(demAmount.to_human_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
assert.strictEqual(demAmount.to_human_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('amount limits', function() {
|
describe('amount limits', function() {
|
||||||
it('max JSON wire limite', function() {
|
it('max JSON wire limite', function() {
|
||||||
assert.strictEqual(Amount.bi_xns_max.toString(), '9000000000000000000');
|
assert.strictEqual(Amount.bi_xns_max.toString(), '100000000000000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('max JSON wire limite', function() {
|
it('max JSON wire limite', function() {
|
||||||
assert.strictEqual(Amount.bi_xns_min.toString(), '-9000000000000000000');
|
assert.strictEqual(Amount.bi_xns_min.toString(), '-100000000000000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('max mantissa value', function() {
|
it('max mantissa value', function() {
|
||||||
@@ -1196,60 +1215,57 @@ describe('Amount', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('from_json minimum XRP', function() {
|
it('from_json minimum XRP', function() {
|
||||||
console.log('max', Amount.bi_xns_max.toString());
|
var amt = Amount.from_json('-100000000000000000');
|
||||||
var amt = Amount.from_json('-9000000000000000000');
|
assert.strictEqual(amt.to_json(), '-100000000000000000');
|
||||||
assert.strictEqual(amt.to_json(), '-9000000000000000000');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json maximum XRP', function() {
|
it('from_json maximum XRP', function() {
|
||||||
var amt = Amount.from_json('-9000000000000000000');
|
var amt = Amount.from_json('100000000000000000');
|
||||||
assert.strictEqual(amt.to_json(), '-9000000000000000000');
|
assert.strictEqual(amt.to_json(), '100000000000000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json less than minimum XRP', function() {
|
it('from_json less than minimum XRP', function() {
|
||||||
var amt = Amount.from_json('-9000000000000000001');
|
assert.throws(function() {
|
||||||
assert.strictEqual(amt.to_json(), '0');
|
Amount.from_json('-100000000000000001');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json more than maximum XRP', function() {
|
it('from_json more than maximum XRP', function() {
|
||||||
var amt = Amount.from_json('9000000000000000001');
|
assert.throws(function() {
|
||||||
assert.strictEqual(amt.to_json(), '0');
|
Amount.from_json('100000000000000001');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json minimum IOU', function() {
|
it('from_json minimum IOU', function() {
|
||||||
var amt = Amount.from_json('-1e-81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
var amt = Amount.from_json('-1e-81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
|
|
||||||
assert.strictEqual(amt.to_text(), '-1000000000000000e-96');
|
assert.strictEqual(amt.to_text(), '-1000000000000000e-96');
|
||||||
assert.strictEqual(amt.to_text(), Amount.min_value);
|
assert.strictEqual(amt.to_text(), Amount.min_value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json exceed minimum IOU', function() {
|
it('from_json exceed minimum IOU', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
Amount.from_json('-1e-82/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
|
Amount.from_json('-1e-82/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
}, 'Exceeding min value of ' + Amount.min_value);
|
}, 'Exceeding min value of ' + Amount.min_value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json maximum IOU', function() {
|
it('from_json maximum IOU', function() {
|
||||||
var amt = Amount.from_json('9999999999999999e80/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
var amt = Amount.from_json('9999999999999999e80/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
|
|
||||||
assert.strictEqual(amt.to_text(), '9999999999999999e80');
|
assert.strictEqual(amt.to_text(), '9999999999999999e80');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json exceed maximum IOU', function() {
|
it('from_json exceed maximum IOU', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
Amount.from_json('9999999999999999e81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
|
Amount.from_json('9999999999999999e81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
}, 'Exceeding max value of ' + Amount.max_value);
|
}, 'Exceeding max value of ' + Amount.max_value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json normalize mantissa to valid max range, lost significant digits', function() {
|
it('from_json normalize mantissa to valid max range, lost significant digits', function() {
|
||||||
var amt = Amount.from_json('99999999999999999999999999999999/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
var amt = Amount.from_json('99999999999999999999999999999999/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
|
|
||||||
assert.strictEqual(amt.to_text(), '9999999999999999e16');
|
assert.strictEqual(amt.to_text(), '9999999999999999e16');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('from_json normalize mantissa to min valid range, lost significant digits', function() {
|
it('from_json normalize mantissa to min valid range, lost significant digits', function() {
|
||||||
var amt = Amount.from_json('-0.0000000000000000000000001/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
var amt = Amount.from_json('-0.0000000000000000000000001/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
|
|
||||||
assert.strictEqual(amt.to_text(), '-1000000000000000e-40');
|
assert.strictEqual(amt.to_text(), '-1000000000000000e-40');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
66
test/base-test.js
Normal file
66
test/base-test.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
'use strict';
|
||||||
|
var assert = require('assert');
|
||||||
|
var Base = require('ripple-lib').Base;
|
||||||
|
var fixtures = require('./fixtures/base58.json');
|
||||||
|
|
||||||
|
function digitArray(str) {
|
||||||
|
return str.split('').map(function(d) {
|
||||||
|
return parseInt(d, 10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToByteArray(hex) {
|
||||||
|
var byteArray = [];
|
||||||
|
for (var i = 0; i < hex.length / 2; i++) {
|
||||||
|
byteArray.push(parseInt(hex.slice(2 * i, 2 * i + 2), 16));
|
||||||
|
}
|
||||||
|
return byteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Base', function() {
|
||||||
|
describe('encode_check', function() {
|
||||||
|
it('0', function () {
|
||||||
|
var encoded = Base.encode_check(0, digitArray('00000000000000000000'));
|
||||||
|
assert.strictEqual(encoded, 'rrrrrrrrrrrrrrrrrrrrrhoLvTp');
|
||||||
|
});
|
||||||
|
it('1', function () {
|
||||||
|
var encoded = Base.encode_check(0, digitArray('00000000000000000001'));
|
||||||
|
assert.strictEqual(encoded, 'rrrrrrrrrrrrrrrrrrrrBZbvji');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('decode_check', function() {
|
||||||
|
it('rrrrrrrrrrrrrrrrrrrrrhoLvTp', function() {
|
||||||
|
var decoded = Base.decode_check(0, 'rrrrrrrrrrrrrrrrrrrrrhoLvTp');
|
||||||
|
assert(decoded.equals(0));
|
||||||
|
});
|
||||||
|
it('rrrrrrrrrrrrrrrrrrrrBZbvji', function() {
|
||||||
|
var decoded = Base.decode_check(0, 'rrrrrrrrrrrrrrrrrrrrBZbvji');
|
||||||
|
assert(decoded.equals(1));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('decode-encode identity', function() {
|
||||||
|
it('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function() {
|
||||||
|
var decoded = Base.decode('rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
|
var encoded = Base.encode(decoded);
|
||||||
|
assert.strictEqual(encoded, 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('encode', function() {
|
||||||
|
it('fixtures', function() {
|
||||||
|
for (var i = 0; i < fixtures.ripple.length; i++) {
|
||||||
|
var testCase = fixtures.ripple[i];
|
||||||
|
var encoded = Base.encode(hexToByteArray(testCase.hex));
|
||||||
|
assert.strictEqual(encoded, testCase.string);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('decode', function() {
|
||||||
|
it('fixtures', function() {
|
||||||
|
for (var i = 0; i < fixtures.ripple.length; i++) {
|
||||||
|
var testCase = fixtures.ripple[i];
|
||||||
|
var decoded = Base.decode(testCase.string);
|
||||||
|
assert.deepEqual(decoded, hexToByteArray(testCase.hex));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
var assert = require('assert');
|
|
||||||
var utils = require('./testutils');
|
|
||||||
var Seed = utils.load_module('seed').Seed;
|
|
||||||
var config = require('./testutils').get_config();
|
|
||||||
|
|
||||||
describe('Base58', function() {
|
|
||||||
describe('Seed', function() {
|
|
||||||
it('saESc82Vun7Ta5EJRzGJbrXb5HNYk', function () {
|
|
||||||
var seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
|
|
||||||
assert.strictEqual(seed.to_hex(), 'FF1CF838D02B2CF7B45BAC27F5F24F4F');
|
|
||||||
});
|
|
||||||
it('sp6iDHnmiPN7tQFHm5sCW59ax3hfE', function () {
|
|
||||||
var seed = Seed.from_json('sp6iDHnmiPN7tQFHm5sCW59ax3hfE');
|
|
||||||
assert.strictEqual(seed.to_hex(), '00AD8DA764C3C8AF5F9B8D51C94B9E49');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// vim:sw=2:sts=2:ts=8:et
|
|
||||||
53
test/baseconverter-test.js
Normal file
53
test/baseconverter-test.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
'use strict';
|
||||||
|
var assert = require('assert');
|
||||||
|
var convertBase = require('ripple-lib').convertBase;
|
||||||
|
|
||||||
|
// Test cases from RFC-1924 (a joke RFC)
|
||||||
|
var BASE85 = ('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
+ 'abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~');
|
||||||
|
var BASE10 = BASE85.slice(0, 10);
|
||||||
|
var BASE16 = BASE85.slice(0, 16);
|
||||||
|
|
||||||
|
var DATA16 = '108000000000000000080800200C417A';
|
||||||
|
var DATA10 = '21932261930451111902915077091070067066';
|
||||||
|
var DATA85 = '4)+k&C#VzJ4br>0wv%Yp';
|
||||||
|
|
||||||
|
function encode(digitArray, encoding) {
|
||||||
|
return digitArray.map(function(i) {
|
||||||
|
return encoding.charAt(i);
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function decode(encoded, encoding) {
|
||||||
|
return encoded.split('').map(function(c) {
|
||||||
|
return encoding.indexOf(c);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertBaseEncoded(value, fromEncoding, toEncoding) {
|
||||||
|
var digitArray = decode(value, fromEncoding);
|
||||||
|
var converted = convertBase(digitArray, fromEncoding.length,
|
||||||
|
toEncoding.length);
|
||||||
|
return encode(converted, toEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('convertBase', function() {
|
||||||
|
it('DEC -> HEX', function () {
|
||||||
|
assert.strictEqual(convertBaseEncoded(DATA10, BASE10, BASE16), DATA16);
|
||||||
|
});
|
||||||
|
it('HEX -> DEC', function () {
|
||||||
|
assert.strictEqual(convertBaseEncoded(DATA16, BASE16, BASE10), DATA10);
|
||||||
|
});
|
||||||
|
it('DEC -> B85', function () {
|
||||||
|
assert.strictEqual(convertBaseEncoded(DATA10, BASE10, BASE85), DATA85);
|
||||||
|
});
|
||||||
|
it('HEX -> B85', function () {
|
||||||
|
assert.strictEqual(convertBaseEncoded(DATA16, BASE16, BASE85), DATA85);
|
||||||
|
});
|
||||||
|
it('B85 -> DEC', function () {
|
||||||
|
assert.strictEqual(convertBaseEncoded(DATA85, BASE85, BASE10), DATA10);
|
||||||
|
});
|
||||||
|
it('B85 -> HEX', function () {
|
||||||
|
assert.strictEqual(convertBaseEncoded(DATA85, BASE85, BASE16), DATA16);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
/*eslint-disable */
|
||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var currency = require('ripple-lib').Currency;
|
||||||
var currency = utils.load_module('currency').Currency;
|
var timeUtil = require('ripple-lib').utils.time;
|
||||||
var timeUtil = utils.load_module('utils').time;
|
|
||||||
|
|
||||||
describe('Currency', function() {
|
describe('Currency', function() {
|
||||||
describe('json_rewrite', function() {
|
describe('json_rewrite', function() {
|
||||||
@@ -55,6 +56,16 @@ describe('Currency', function() {
|
|||||||
assert(r.is_valid());
|
assert(r.is_valid());
|
||||||
assert.strictEqual('1D2', r.to_json());
|
assert.strictEqual('1D2', r.to_json());
|
||||||
});
|
});
|
||||||
|
it('from_json("1").to_human()', function() {
|
||||||
|
var r = currency.from_json('1');
|
||||||
|
assert(r.is_valid());
|
||||||
|
assert.strictEqual(1, r.to_json());
|
||||||
|
});
|
||||||
|
it('from_json("#$%").to_human()', function() {
|
||||||
|
var r = currency.from_json('#$%');
|
||||||
|
assert(r.is_valid());
|
||||||
|
assert.strictEqual('0000000000000000000000002324250000000000', r.to_json());
|
||||||
|
});
|
||||||
it('from_json("XAU").to_json() hex', function() {
|
it('from_json("XAU").to_json() hex', function() {
|
||||||
var r = currency.from_json("XAU");
|
var r = currency.from_json("XAU");
|
||||||
assert.strictEqual('0000000000000000000000005841550000000000', r.to_json({force_hex: true}));
|
assert.strictEqual('0000000000000000000000005841550000000000', r.to_json({force_hex: true}));
|
||||||
|
|||||||
5
test/fixtures/addresses.js
vendored
Normal file
5
test/fixtures/addresses.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports.ACCOUNT = 'r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59';
|
||||||
|
module.exports.OTHER_ACCOUNT = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo';
|
||||||
|
module.exports.THIRD_ACCOUNT = 'rwBYyfufTzk77zUSKEu4MvixfarC35av1J';
|
||||||
|
module.exports.FOURTH_ACCOUNT = 'rJnZ4YHCUsHvQu7R6mZohevKJDHFzVD6Zr';
|
||||||
|
module.exports.ISSUER = 'rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM';
|
||||||
141
test/fixtures/base58.json
vendored
Normal file
141
test/fixtures/base58.json
vendored
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
{
|
||||||
|
"ripple": [
|
||||||
|
{
|
||||||
|
"hex": "",
|
||||||
|
"string": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "61",
|
||||||
|
"string": "pg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "626262",
|
||||||
|
"string": "2sgV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "636363",
|
||||||
|
"string": "2PNi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "73696d706c792061206c6f6e6720737472696e67",
|
||||||
|
"string": "pcEuFj68N1S8n9qHX1tmKpCCFLvp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "00eb15231dfceb60925886b67d065299925915aeb172c06647",
|
||||||
|
"string": "r4Srf52g9jJgTHDrVXjvLUN8ZuQsiJDN9L"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "516b6fcd0f",
|
||||||
|
"string": "wB8LTmg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "bf4f89001e670274dd",
|
||||||
|
"string": "sSNosLWLoP8tU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "572e4794",
|
||||||
|
"string": "sNE7fm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "ecac89cad93923c02321",
|
||||||
|
"string": "NJDM3diCXwauyw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "10c8511e",
|
||||||
|
"string": "Rtnzm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "00000000000000000000",
|
||||||
|
"string": "rrrrrrrrrr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e",
|
||||||
|
"string": "nHxrnHEGyeFpUCPx1JKepCXJ1UV8nDN5yoeGGEaJZjGbTR8qC5D"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187",
|
||||||
|
"string": "ra7jcY4BG9GTKhuqpCfyYNbu5CqUzoLMGS"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bitcoin": [
|
||||||
|
{
|
||||||
|
"hex": "",
|
||||||
|
"string": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "61",
|
||||||
|
"string": "2g"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "626262",
|
||||||
|
"string": "a3gV"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "636363",
|
||||||
|
"string": "aPEr"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "73696d706c792061206c6f6e6720737472696e67",
|
||||||
|
"string": "2cFupjhnEsSn59qHXstmK2ffpLv2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "00eb15231dfceb60925886b67d065299925915aeb172c06647",
|
||||||
|
"string": "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "516b6fcd0f",
|
||||||
|
"string": "ABnLTmg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "bf4f89001e670274dd",
|
||||||
|
"string": "3SEo3LWLoPntC"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "572e4794",
|
||||||
|
"string": "3EFU7m"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "ecac89cad93923c02321",
|
||||||
|
"string": "EJDM8drfXA6uyA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "10c8511e",
|
||||||
|
"string": "Rt5zm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "00000000000000000000",
|
||||||
|
"string": "1111111111"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e",
|
||||||
|
"string": "5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hex": "003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187",
|
||||||
|
"string": "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"invalid": [
|
||||||
|
{
|
||||||
|
"description": "non-base58 string",
|
||||||
|
"string": "invalid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "non-base58 alphabet",
|
||||||
|
"string": "c2F0b3NoaQo="
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "leading whitespace",
|
||||||
|
"string": " 1111111111"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "trailing whitespace",
|
||||||
|
"string": "1111111111 "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "unexpected character after whitespace",
|
||||||
|
"string": " \t\n\u000b\f\r skip \r\f\u000b\n\t a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
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"
|
||||||
|
}
|
||||||
857
test/fixtures/orderbook.js
vendored
Normal file
857
test/fixtures/orderbook.js
vendored
Normal file
@@ -0,0 +1,857 @@
|
|||||||
|
/*eslint-disable max-len */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var _ = require('lodash');
|
||||||
|
var addresses = require('./addresses');
|
||||||
|
var Meta = require('ripple-lib').Meta;
|
||||||
|
|
||||||
|
module.exports.FIAT_BALANCE = '10';
|
||||||
|
module.exports.NATIVE_BALANCE = '55';
|
||||||
|
module.exports.NATIVE_BALANCE_PREVIOUS = '100';
|
||||||
|
|
||||||
|
module.exports.TAKER_GETS = '19.84580331';
|
||||||
|
module.exports.TAKER_GETS_FINAL = '18.84580331';
|
||||||
|
module.exports.TAKER_PAYS = '3878342440';
|
||||||
|
module.exports.TAKER_PAYS_FINAL = '3078342440';
|
||||||
|
module.exports.OTHER_TAKER_GETS = '4.9656112525';
|
||||||
|
module.exports.OTHER_TAKER_GETS_FINAL = '3.9656112525';
|
||||||
|
module.exports.OTHER_TAKER_PAYS = '972251352';
|
||||||
|
module.exports.OTHER_TAKER_PAYS_FINAL = '902251352';
|
||||||
|
|
||||||
|
module.exports.LEDGER_INDEX = '06AFB03237286C1566CD649CFD5388C2C1F5BEFC5C3302A1962682803A9946FA';
|
||||||
|
module.exports.OTHER_LEDGER_INDEX = 'D3338DA77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252';
|
||||||
|
|
||||||
|
module.exports.TRANSFER_RATE = 1002000000;
|
||||||
|
|
||||||
|
module.exports.fiatOffers = function (options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
account_funds: '318.3643710638508',
|
||||||
|
other_account_funds: '235.0194163432668'
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F15E821839FB',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000001897',
|
||||||
|
PreviousTxnID: '11BA57676711A42C2FC2191EAEE98023B04627DFA84926B0C8E9D61A9CAF13AD',
|
||||||
|
PreviousTxnLgrSeq: 8265601,
|
||||||
|
Sequence: 531927,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.TAKER_GETS
|
||||||
|
},
|
||||||
|
taker_gets_funded: '100',
|
||||||
|
is_fully_funded: true,
|
||||||
|
TakerPays: module.exports.TAKER_PAYS,
|
||||||
|
index: module.exports.LEDGER_INDEX,
|
||||||
|
owner_funds: options.account_funds,
|
||||||
|
quality: '195423807.2109563'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F4C3362FE1D0',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '00000000000063CC',
|
||||||
|
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||||
|
PreviousTxnLgrSeq: 8265523,
|
||||||
|
Sequence: 1139002,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '4.9656112525'
|
||||||
|
},
|
||||||
|
taker_gets_funded: '100',
|
||||||
|
is_fully_funded: true,
|
||||||
|
TakerPays: '972251352',
|
||||||
|
index: 'X2K98DB77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252',
|
||||||
|
owner_funds: options.account_funds,
|
||||||
|
quality: '195796912.5171664'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.OTHER_ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F4C3362FE1D0',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '00000000000063CC',
|
||||||
|
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||||
|
PreviousTxnLgrSeq: 8265523,
|
||||||
|
Sequence: 1139002,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.OTHER_TAKER_GETS
|
||||||
|
},
|
||||||
|
taker_gets_funded: '100',
|
||||||
|
is_fully_funded: true,
|
||||||
|
TakerPays: module.exports.OTHER_TAKER_PAYS,
|
||||||
|
index: module.exports.OTHER_LEDGER_INDEX,
|
||||||
|
owner_funds: options.other_account_funds,
|
||||||
|
quality: '195796912.5171664'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.NATIVE_OFFERS = [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4C124AF94ED1781B',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '00000000000063CA',
|
||||||
|
PreviousTxnID: '51C64E0B300E9C0E877BA3E79B4ED1DBD5FDDCE58FA1A8FDA5F8DDF139787A24',
|
||||||
|
PreviousTxnLgrSeq: 8265275,
|
||||||
|
Sequence: 1138918,
|
||||||
|
TakerGets: '50',
|
||||||
|
taker_gets_funded: '100',
|
||||||
|
is_fully_funded: true,
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '5'
|
||||||
|
},
|
||||||
|
index: 'DC003E09AD1306FBBD1957C955EE668E429CC85B0EC0EC17297F6676E6108DE7',
|
||||||
|
owner_funds: '162110617177',
|
||||||
|
quality: '0.000000005148984210454555'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: 'DFA3B6DDAB58C7E8E5D944E736DA4B7046C30E4F460FD9DE4C124B054BAD1D79',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000001896',
|
||||||
|
PreviousTxnID: '9B21C7A4B66DC1CD5FC9D85C821C4CAA8F80E437582BAD11E88A1E9E6C7AA59C',
|
||||||
|
PreviousTxnLgrSeq: 8265118,
|
||||||
|
Sequence: 531856,
|
||||||
|
TakerGets: '10',
|
||||||
|
taker_gets_funded: '100',
|
||||||
|
is_fully_funded: true,
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '20'
|
||||||
|
},
|
||||||
|
index: '7AC0458676A54E99FAA5ED0A56CD0CB814D3DEFE1C7874F0BB39875D60668E41',
|
||||||
|
owner_funds: '430527438338',
|
||||||
|
quality: '0.000000005149035697347961'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.OTHER_ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D06F4C3362FE1D0',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '00000000000063CC',
|
||||||
|
PreviousTxnID: 'CD77500EF28984BFC123E8A257C10E44FF486EA8FC43E1356C42BD6DB853A602',
|
||||||
|
PreviousTxnLgrSeq: 8265523,
|
||||||
|
Sequence: 1139002,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '4.9656112525'
|
||||||
|
},
|
||||||
|
TakerPays: '972251352',
|
||||||
|
index: 'D3338DA77BA23122FB5647B74B53636AB54BE246D4B21707C9D6887DEB334252',
|
||||||
|
owner_funds: '235.0194163432668',
|
||||||
|
quality: '195796912.5171664'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports.REQUEST_OFFERS = [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000000',
|
||||||
|
PreviousTxnID: '9BB337CC8B34DC8D1A3FFF468556C8BA70977C37F7436439D8DA19610F214AD1',
|
||||||
|
PreviousTxnLgrSeq: 8342933,
|
||||||
|
Sequence: 195,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'BTC',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '0.1129232560043778'
|
||||||
|
},
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '56.06639660617357'
|
||||||
|
},
|
||||||
|
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||||
|
owner_funds: '0.1129267125000245',
|
||||||
|
quality: '496.4999999999999'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.OTHER_ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 461498565,
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000144',
|
||||||
|
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||||
|
PreviousTxnLgrSeq: 8342469,
|
||||||
|
Sequence: 29354,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'BTC',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '0.2'
|
||||||
|
},
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '99.72233516476456'
|
||||||
|
},
|
||||||
|
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||||
|
owner_funds: '0.950363009783092',
|
||||||
|
quality: '498.6116758238228'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.THIRD_ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 461498565,
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000144',
|
||||||
|
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||||
|
PreviousTxnLgrSeq: 8342469,
|
||||||
|
Sequence: 29356,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'BTC',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '0.5'
|
||||||
|
},
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '99.72233516476456'
|
||||||
|
},
|
||||||
|
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||||
|
owner_funds: '0.950363009783092',
|
||||||
|
quality: '498.6116758238228'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.THIRD_ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 461498565,
|
||||||
|
Flags: 131078,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000144',
|
||||||
|
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||||
|
PreviousTxnLgrSeq: 8342469,
|
||||||
|
Sequence: 29354,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'BTC',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '0.5'
|
||||||
|
},
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '99.72233516476456'
|
||||||
|
},
|
||||||
|
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||||
|
owner_funds: '0.950363009783092',
|
||||||
|
quality: '199.4446703295291'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports.REQUEST_OFFERS_NATIVE = [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711A3A4254F5000',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000000',
|
||||||
|
Sequence: 195,
|
||||||
|
TakerGets: '1000',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '56.06639660617357'
|
||||||
|
},
|
||||||
|
index: 'B6BC3B0F87976370EE11F5575593FE63AA5DC1D602830DC96F04B2D597F044BF',
|
||||||
|
owner_funds: '600',
|
||||||
|
quality: '.0560663966061735'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.OTHER_ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 461498565,
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000144',
|
||||||
|
Sequence: 29354,
|
||||||
|
TakerGets: '2000',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '99.72233516476456'
|
||||||
|
},
|
||||||
|
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||||
|
owner_funds: '4000',
|
||||||
|
quality: '0.049861167582382'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.THIRD_ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 461498565,
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000144',
|
||||||
|
Sequence: 29356,
|
||||||
|
TakerGets: '2000',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '99.72233516476456'
|
||||||
|
},
|
||||||
|
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||||
|
owner_funds: '3900',
|
||||||
|
quality: '0.049861167582382'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.THIRD_ACCOUNT,
|
||||||
|
BookDirectory: '6EAB7C172DEFA430DBFAD120FDC373B5F5AF8B191649EC985711B6D8C62EF414',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 461498565,
|
||||||
|
Flags: 131078,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000144',
|
||||||
|
PreviousTxnID: 'C8296B9CCA6DC594C7CD271C5D8FD11FEE380021A07768B25935642CDB37048A',
|
||||||
|
PreviousTxnLgrSeq: 8342469,
|
||||||
|
Sequence: 29354,
|
||||||
|
TakerGets: '2000',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '99.72233516476456'
|
||||||
|
},
|
||||||
|
index: 'A437D85DF80D250F79308F2B613CF5391C7CF8EE9099BC4E553942651CD9FA86',
|
||||||
|
quality: '0.049861167582382'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports.QUALITY_OFFERS = [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C1AFE1EE71A605F',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000009',
|
||||||
|
PreviousTxnID: 'BCA728C17DBA10F100C41D4EF8B37318F33BC6156E94DB16703D2A1EE43DCCE6',
|
||||||
|
PreviousTxnLgrSeq: 11929146,
|
||||||
|
Sequence: 668643,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||||
|
value: '301.3426005599325'
|
||||||
|
},
|
||||||
|
TakerPays: '22895281765',
|
||||||
|
index: '79B34D7DF703580B86099EFD6B2E419AA39A585A50C82A3F9B446721B7C1490C',
|
||||||
|
owner_funds: '5910.437716613066',
|
||||||
|
quality: '75977580.74216543'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// This fixture is to exercise a bug where taker_pays_funded = taker_gets_funded * quality
|
||||||
|
// has decimal amounts.
|
||||||
|
module.exports.DECIMAL_TAKER_PAYS_FUNDED_OFFERS = [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5D0689673FA9094A',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000006',
|
||||||
|
PreviousTxnID: 'C1BB04CE39E30BF5982B7660793723E9B3A832F5B458DB1C5938F4737E0E9ABF',
|
||||||
|
PreviousTxnLgrSeq: 11631257,
|
||||||
|
Sequence: 2936,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '9280.04'
|
||||||
|
},
|
||||||
|
TakerPays: '1707459061637',
|
||||||
|
index: '89D85BBE91E0F419953EB89CE62E194922ED930EE57BE0C62FCC3B22DDB20852',
|
||||||
|
owner_funds: '9280.037154029904',
|
||||||
|
quality: '183992640.2943306',
|
||||||
|
taker_gets_funded: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '9261.514125778347'
|
||||||
|
},
|
||||||
|
taker_pays_funded: '1704050437125'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports.bookOffersResponse = function (options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
account_funds: '2010.027702881682',
|
||||||
|
other_account_funds: '24.06086596039299',
|
||||||
|
third_account_funds: '9071.40090264774',
|
||||||
|
fourth_account_funds: '7244.053477923128'
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
offers: [
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C188F5B29EE1C14',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000006762',
|
||||||
|
PreviousTxnID: '5F08192C82CD3A598D29B51FCCDE29B6709EBCB454A3CD540C32F7A79EE7CB26',
|
||||||
|
PreviousTxnLgrSeq: 11558364,
|
||||||
|
Sequence: 1689777,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '79.39192374'
|
||||||
|
},
|
||||||
|
TakerPays: '5488380479',
|
||||||
|
index: 'D9F821C8687E0D0EDEFF05EBB53CFDC81C5F9C4C354DAACB11F6676B5E14AEF5',
|
||||||
|
owner_funds: options.account_funds,
|
||||||
|
quality: '69130211.4932226'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.OTHER_ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18949C72B26C2A',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000001',
|
||||||
|
PreviousTxnID: '038ED9ACC10211A8F6768729F36B74729CECCD33057837E160131675B272E532',
|
||||||
|
PreviousTxnLgrSeq: 11558374,
|
||||||
|
Sequence: 931088,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '24.060765960393'
|
||||||
|
},
|
||||||
|
TakerPays: '1664716059',
|
||||||
|
index: '8845F212A8B53004A14C8C029FAF51B53266C66B49281A72F6A8F41CD92FDE99',
|
||||||
|
owner_funds: options.other_account_funds,
|
||||||
|
quality: '69187991.0116049',
|
||||||
|
taker_gets_funded: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '24.01284027983332'
|
||||||
|
},
|
||||||
|
taker_pays_funded: '1661400177'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.THIRD_ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18949C764EA14E',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000009',
|
||||||
|
PreviousTxnID: '62B96C0E0D86827BCE59ABDCAD146CC0B09404FE5BC86E712FB6F4E473016C63',
|
||||||
|
PreviousTxnLgrSeq: 11558234,
|
||||||
|
Sequence: 617872,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '712.60995'
|
||||||
|
},
|
||||||
|
TakerPays: '49304051247',
|
||||||
|
index: '9E5C13908F67146AC35A711A17E5EB75771FDDA816C9532891DC90F29A6A4C10',
|
||||||
|
owner_funds: options.third_account_funds,
|
||||||
|
quality: '69187991.61729358'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.FOURTH_ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18AA2E761B7EE6',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000000511',
|
||||||
|
PreviousTxnID: 'F18AED5EC1E7529EF03AF23ADA85F7625AA308278BACE1851F336443AA3DAAEA',
|
||||||
|
PreviousTxnLgrSeq: 11558336,
|
||||||
|
Sequence: 662712,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '288.08'
|
||||||
|
},
|
||||||
|
TakerPays: '20000000000',
|
||||||
|
index: '606B3FC9199D5122F1DCC73EC1629E40C8A838D58AC67315A78D76699D960705',
|
||||||
|
owner_funds: options.fourth_account_funds,
|
||||||
|
quality: '69425159.67786726'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C18C3D9EF58005A',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 0,
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
OwnerNode: '0000000000006762',
|
||||||
|
PreviousTxnID: 'E3A0240001B03E4F16C4BA6C2B0CB00C01413BE331ABE9E782B6A975DC936618',
|
||||||
|
PreviousTxnLgrSeq: 11558318,
|
||||||
|
Sequence: 1689755,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: '196.460002'
|
||||||
|
},
|
||||||
|
TakerPays: '13694716399',
|
||||||
|
index: '9A5D0AA37EA0889B876E9A3E552CACDB28BA5A3CD482A528992CD0CCFC09F6E8',
|
||||||
|
quality: '69707402.31897178'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.MODIFIED_NODES = [
|
||||||
|
{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: 'E2B91A0A170BCC2BEC5C44B492D9B672888D9267A900330F5C08953CAA35D973',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 131072,
|
||||||
|
OwnerNode: '0000000000000001',
|
||||||
|
Sequence: 538,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.TAKER_GETS_FINAL
|
||||||
|
},
|
||||||
|
TakerPays: module.exports.TAKER_PAYS_FINAL
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
LedgerIndex: module.exports.LEDGER_INDEX,
|
||||||
|
PreviousFields: {
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.TAKER_GETS
|
||||||
|
},
|
||||||
|
TakerPays: module.exports.TAKER_PAYS
|
||||||
|
},
|
||||||
|
PreviousTxnID: '5135DF8678727A70491DE512E5F0FE586E7C1E866492293B8898BF8191CFCAEB',
|
||||||
|
PreviousTxnLgrSeq: 11676651
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: addresses.OTHER_ACCOUNT,
|
||||||
|
BookDirectory: 'E2B91A0A170BCC2BEC5C44B492D9B672888D9267A900330F5C08953CAA35D973',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Flags: 131072,
|
||||||
|
OwnerNode: '0000000000000001',
|
||||||
|
Sequence: 538,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.OTHER_TAKER_GETS_FINAL
|
||||||
|
},
|
||||||
|
TakerPays: module.exports.OTHER_TAKER_PAYS_FINAL
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
LedgerIndex: module.exports.OTHER_LEDGER_INDEX,
|
||||||
|
PreviousFields: {
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.OTHER_TAKER_GETS
|
||||||
|
},
|
||||||
|
TakerPays: module.exports.OTHER_TAKER_PAYS
|
||||||
|
},
|
||||||
|
PreviousTxnID: '5135DF8678727A70491DE512E5F0FE586E7C1E866492293B8898BF8191CFCAEB',
|
||||||
|
PreviousTxnLgrSeq: 11676651
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
module.exports.transactionWithRippleState = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
account: addresses.ACCOUNT,
|
||||||
|
balance: module.exports.FIAT_BALANCE
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: new Meta({
|
||||||
|
AffectedNodes: [{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Balance: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||||
|
value: options.balance
|
||||||
|
},
|
||||||
|
Flags: 131072,
|
||||||
|
HighLimit: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: options.issuer,
|
||||||
|
value: '100'
|
||||||
|
},
|
||||||
|
HighNode: '0000000000000000',
|
||||||
|
LowLimit: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: options.account,
|
||||||
|
value: '0'
|
||||||
|
},
|
||||||
|
LowNode: '0000000000000000'
|
||||||
|
},
|
||||||
|
PreviousFields: {
|
||||||
|
Balance: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'rrrrrrrrrrrrrrrrrrrrBZbvji',
|
||||||
|
value: '0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'RippleState',
|
||||||
|
LedgerIndex: 'EA4BF03B4700123CDFFB6EB09DC1D6E28D5CEB7F680FB00FC24BC1C3BB2DB959',
|
||||||
|
PreviousTxnID: '53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8',
|
||||||
|
PreviousTxnLgrSeq: 343570
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithAccountRoot = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
account: addresses.ACCOUNT,
|
||||||
|
balance: module.exports.NATIVE_BALANCE,
|
||||||
|
previous_balance: module.exports.NATIVE_BALANCE_PREVIOUS
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: new Meta({
|
||||||
|
AffectedNodes: [{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: options.account,
|
||||||
|
Balance: options.balance,
|
||||||
|
Flags: 0,
|
||||||
|
OwnerCount: 1,
|
||||||
|
Sequence: 2
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
LedgerIndex: '4F83A2CF7E70F77F79A307E6A472BFC2585B806A70833CCD1C26105BAE0D6E05',
|
||||||
|
PreviousFields: {
|
||||||
|
Balance: options.previous_balance,
|
||||||
|
OwnerCount: 0,
|
||||||
|
Sequence: 1
|
||||||
|
},
|
||||||
|
PreviousTxnID: 'B24159F8552C355D35E43623F0E5AD965ADBF034D482421529E2703904E1EC09',
|
||||||
|
PreviousTxnLgrSeq: 16154
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithInvalidAccountRoot = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
account: addresses.ACCOUNT,
|
||||||
|
balance: module.exports.NATIVE_BALANCE
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: new Meta({
|
||||||
|
AffectedNodes: [{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: options.account,
|
||||||
|
Balance: options.balance,
|
||||||
|
Flags: 0,
|
||||||
|
OwnerCount: 3,
|
||||||
|
Sequence: 188
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
LedgerIndex: 'B33FDD5CF3445E1A7F2BE9B06336BEBD73A5E3EE885D3EF93F7E3E2992E46F1A',
|
||||||
|
PreviousTxnID: 'E9E1988A0F061679E5D14DE77DB0163CE0BBDC00F29E396FFD1DA0366E7D8904',
|
||||||
|
PreviousTxnLgrSeq: 195455
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithCreatedOffer = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
account: addresses.ACCOUNT,
|
||||||
|
amount: '1.9951'
|
||||||
|
});
|
||||||
|
|
||||||
|
var meta = new Meta({
|
||||||
|
AffectedNodes: [
|
||||||
|
{
|
||||||
|
CreatedNode: {
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
LedgerIndex: 'AF3C702057C9C47DB9E809FD8C76CD22521012C5CC7AE95D914EC9E226F1D7E5',
|
||||||
|
NewFields: {
|
||||||
|
Account: options.account,
|
||||||
|
BookDirectory: '7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F211CEE1E0697A0',
|
||||||
|
Flags: 131072,
|
||||||
|
Sequence: 1404,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: options.amount
|
||||||
|
},
|
||||||
|
TakerPays: module.exports.TAKER_PAYS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.getAffectedBooks();
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: meta,
|
||||||
|
transaction: {
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
owner_funds: '2010.027702881682'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithDeletedOffer = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
transaction_type: 'OfferCreate'
|
||||||
|
});
|
||||||
|
|
||||||
|
var meta = new Meta({
|
||||||
|
AffectedNodes: [
|
||||||
|
{
|
||||||
|
DeletedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: addresses.ACCOUNT,
|
||||||
|
BookDirectory: '3B95C29205977C2136BBC70F21895F8C8F471C8522BF446E570463F9CDB31517',
|
||||||
|
BookNode: '0000000000000000',
|
||||||
|
Expiration: 477086871,
|
||||||
|
Flags: 131072,
|
||||||
|
OwnerNode: '0000000000000979',
|
||||||
|
PreviousTxnID: 'DDD2AB60A2AA1690A6CB99B094BFD2E39A81AFF2AA91B5E4049D2C96A4BC8EBA',
|
||||||
|
PreviousTxnLgrSeq: 11674760,
|
||||||
|
Sequence: 85006,
|
||||||
|
TakerGets: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: addresses.ISSUER,
|
||||||
|
value: module.exports.TAKER_GETS
|
||||||
|
},
|
||||||
|
TakerPays: module.exports.TAKER_PAYS
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'Offer',
|
||||||
|
LedgerIndex: module.exports.LEDGER_INDEX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.getAffectedBooks();
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: meta,
|
||||||
|
transaction: {
|
||||||
|
TransactionType: options.transaction_type,
|
||||||
|
owner_funds: '2010.027702881682'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithModifiedOffer = function() {
|
||||||
|
var meta = new Meta({
|
||||||
|
AffectedNodes: module.exports.MODIFIED_NODES.slice(0, 1)
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.getAffectedBooks();
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: meta,
|
||||||
|
transaction: {
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
owner_funds: '2010.027702881682'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithModifiedOffers = function() {
|
||||||
|
var meta = new Meta({
|
||||||
|
AffectedNodes: module.exports.MODIFIED_NODES
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.getAffectedBooks();
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: meta,
|
||||||
|
transaction: {
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
owner_funds: '2010.027702881682'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.transactionWithNoNodes = function() {
|
||||||
|
var meta = new Meta({
|
||||||
|
AffectedNodes: []
|
||||||
|
});
|
||||||
|
|
||||||
|
meta.getAffectedBooks();
|
||||||
|
|
||||||
|
return {
|
||||||
|
mmeta: meta,
|
||||||
|
transaction: {
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
owner_funds: '2010.027702881682'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.accountInfoResponse = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
_.defaults(options, {
|
||||||
|
account: addresses.ISSUER
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
account_data: {
|
||||||
|
Account: options.account,
|
||||||
|
Balance: '6156166959471',
|
||||||
|
Domain: '6269747374616D702E6E6574',
|
||||||
|
EmailHash: '5B33B93C7FFE384D53450FC666BB11FB',
|
||||||
|
Flags: 131072,
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
OwnerCount: 0,
|
||||||
|
PreviousTxnID: '6A7D0AB36CBA6884FDC398254BC67DE7E0B4887E9B0252568391102FBB854C09',
|
||||||
|
PreviousTxnLgrSeq: 8344426,
|
||||||
|
Sequence: 561,
|
||||||
|
TransferRate: module.exports.TRANSFER_RATE,
|
||||||
|
index: 'B7D526FDDF9E3B3F95C3DC97C353065B0482302500BBB8051A5C090B596C6133',
|
||||||
|
urlgravatar: 'http:www.gravatar.com/avatar/5b33b93c7ffe384d53450fc666bb11fb'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
788
test/fixtures/pathfind.json
vendored
Normal file
788
test/fixtures/pathfind.json
vendored
Normal file
@@ -0,0 +1,788 @@
|
|||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "path_find",
|
||||||
|
"alternatives": [
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rwBWBFZrbLzHoe3PhwWYv89iHJdxAFrxcB",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rULnR9YhAkj9HrcxAcudzBhaXRSqT7zJkq",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "r9hEDb4xBGRfBCcX3E4FirDWQBAYtpxC8K",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": "64235"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "BTC",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.000003810807915357615"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"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": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "CHF",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.004290898000000001"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||||
|
"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": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "CNY",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.006251153484651535"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||||
|
"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": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "DYM",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.001503"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"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": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "EUR",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.0008032032"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"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": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "JPY",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.12872694"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"paths_computed": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||||
|
"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": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rrpNnNLKrartuEqfJGpqyDwPj1AFPg9vn1",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rpHgehzdpfWRXKvSv6duKvVuo1aZVimdaT",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"account": "rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "XRP",
|
||||||
|
"type": 16,
|
||||||
|
"type_hex": "0000000000000010"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||||
|
"type": 48,
|
||||||
|
"type_hex": "0000000000000030"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rHHa9t2kLQyXRbdLkSzEgkzwf9unmFgZs9",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"account": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"type": 1,
|
||||||
|
"type_hex": "0000000000000001"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"source_amount": {
|
||||||
|
"currency": "MXN",
|
||||||
|
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"value": "0.008172391857506362"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"destination_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||||
|
"destination_amount": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
|
||||||
|
"value": "0.001"
|
||||||
|
},
|
||||||
|
"source_account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59"
|
||||||
|
}
|
||||||
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
171
test/fixtures/transaction-offercreate.json
vendored
Normal file
171
test/fixtures/transaction-offercreate.json
vendored
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"engine_result": "tesSUCCESS",
|
||||||
|
"engine_result_code": 0,
|
||||||
|
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||||
|
"ledger_hash": "60A87F43A4A95AF446AE9391CEFC4FD41E24CA632286EBACA8B1337791009D2A",
|
||||||
|
"ledger_index": 11409475,
|
||||||
|
"meta": {
|
||||||
|
"AffectedNodes": [
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Balance": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||||
|
"value": "-2008.589162146675"
|
||||||
|
},
|
||||||
|
"Flags": 2228224,
|
||||||
|
"HighLimit": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rQBgvk1GMACRzpSBrHJNQ6rNfgdzUv2SaX",
|
||||||
|
"value": "1000000000"
|
||||||
|
},
|
||||||
|
"HighNode": "0000000000000000",
|
||||||
|
"LowLimit": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
"LowNode": "000000000000028B"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "RippleState",
|
||||||
|
"LedgerIndex": "10E1B93C71D6FC528B36BFDAD005DFDA8BA4C6EC691ADE225ACD91A18BBBC2BA",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Balance": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||||
|
"value": "-2003.931566739001"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PreviousTxnID": "308FD18F3D42F83F5C7043F2DEAA4B8DDCAF20F564D180D606F00F3E575FEEC5",
|
||||||
|
"PreviousTxnLgrSeq": 11409459
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Account": "rHvo925Q1zmDJbzze6a5L3DfXdvhrwh1oJ",
|
||||||
|
"Balance": "222138630497",
|
||||||
|
"Flags": 0,
|
||||||
|
"OwnerCount": 5,
|
||||||
|
"Sequence": 1040
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"LedgerIndex": "3FB24E2BA13AE12802781D03F263CE28569BF487C766812485E3C286ED990CFC",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Balance": "221810037141"
|
||||||
|
},
|
||||||
|
"PreviousTxnID": "736CEAD2BE2C49285BBC3ADCD1EA42FBB0D1A292E1A03C344234F664FC6EC523",
|
||||||
|
"PreviousTxnLgrSeq": 11409463
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Account": "rQBgvk1GMACRzpSBrHJNQ6rNfgdzUv2SaX",
|
||||||
|
"Balance": "473511395546",
|
||||||
|
"Flags": 0,
|
||||||
|
"OwnerCount": 5,
|
||||||
|
"Sequence": 4094
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"LedgerIndex": "4179A2DBAF895E9D0618A8C0FB2FFDBEAE92E74C275C7992D538484AE20B2140",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Balance": "473839998902",
|
||||||
|
"Sequence": 4093
|
||||||
|
},
|
||||||
|
"PreviousTxnID": "308FD18F3D42F83F5C7043F2DEAA4B8DDCAF20F564D180D606F00F3E575FEEC5",
|
||||||
|
"PreviousTxnLgrSeq": 11409459
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Account": "rHvo925Q1zmDJbzze6a5L3DfXdvhrwh1oJ",
|
||||||
|
"BookDirectory": "4627DFFCFF8B5A265EDBD8AE8C14A52325DBFEDAF4F5C32E5C19107C30E031F0",
|
||||||
|
"BookNode": "0000000000000000",
|
||||||
|
"Flags": 131072,
|
||||||
|
"OwnerNode": "0000000000000000",
|
||||||
|
"Sequence": 1039,
|
||||||
|
"TakerGets": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||||
|
"value": "190.5072902688483"
|
||||||
|
},
|
||||||
|
"TakerPays": "13440289328"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "Offer",
|
||||||
|
"LedgerIndex": "AAD85C591B95855B524675AE73EAEC90D5E4BF32425D36A5B449914ADE33EDD9",
|
||||||
|
"PreviousFields": {
|
||||||
|
"TakerGets": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||||
|
"value": "195.1648856765226"
|
||||||
|
},
|
||||||
|
"TakerPays": "13768882684"
|
||||||
|
},
|
||||||
|
"PreviousTxnID": "736CEAD2BE2C49285BBC3ADCD1EA42FBB0D1A292E1A03C344234F664FC6EC523",
|
||||||
|
"PreviousTxnLgrSeq": 11409463
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Balance": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||||
|
"value": "-459.5348867698966"
|
||||||
|
},
|
||||||
|
"Flags": 2228224,
|
||||||
|
"HighLimit": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rHvo925Q1zmDJbzze6a5L3DfXdvhrwh1oJ",
|
||||||
|
"value": "1000000000"
|
||||||
|
},
|
||||||
|
"HighNode": "0000000000000000",
|
||||||
|
"LowLimit": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
"LowNode": "0000000000000296"
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "RippleState",
|
||||||
|
"LedgerIndex": "CDE76B186BBB028CA4C8A0C6D22085AD1DF8F692920150189343831E2C0C647D",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Balance": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||||
|
"value": "-464.2017973683862"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PreviousTxnID": "5AF91C90CE8AE78FB8ACFFE2AB626936AB2CA4A8D66C25D087A41D4B75C16F39",
|
||||||
|
"PreviousTxnLgrSeq": 11409443
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 10,
|
||||||
|
"TransactionResult": "tesSUCCESS"
|
||||||
|
},
|
||||||
|
"status": "closed",
|
||||||
|
"transaction": {
|
||||||
|
"Account": "rQBgvk1GMACRzpSBrHJNQ6rNfgdzUv2SaX",
|
||||||
|
"Fee": "10000",
|
||||||
|
"Flags": 524288,
|
||||||
|
"Sequence": 4093,
|
||||||
|
"SigningPubKey": "020D6BF674E9ABF3BD8C08BA7CCFA878DC283729240CEC096FC1EE23DA823472C0",
|
||||||
|
"TakerGets": "328593356",
|
||||||
|
"TakerPays": {
|
||||||
|
"currency": "USD",
|
||||||
|
"issuer": "rJy64aCJLP3vf8o3WPKn4iQKtfpjh6voAR",
|
||||||
|
"value": "3.943120281680337"
|
||||||
|
},
|
||||||
|
"TransactionType": "OfferCreate",
|
||||||
|
"TxnSignature": "3045022100FC89A7B7573754B33DA7556D861AC180CFEDD1F72DE9436384540745E3B2DBB4022074EDA52B2BE636A002743A49B791FD362B70B0DAFB8CC0AF3C49EDC261D0EA58",
|
||||||
|
"date": 475884270,
|
||||||
|
"hash": "FC7A9D19B40B7BCC66E3A38536E7DB888925BF935440307F6A4F55818E141BAC",
|
||||||
|
"owner_funds": "473466395546"
|
||||||
|
},
|
||||||
|
"type": "transaction",
|
||||||
|
"validated": true
|
||||||
|
}
|
||||||
19
test/fixtures/transaction-proposed.json
vendored
Normal file
19
test/fixtures/transaction-proposed.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"engine_result": "tesSUCCESS",
|
||||||
|
"engine_result_code": 0,
|
||||||
|
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||||
|
"ledger_current_index": 114177,
|
||||||
|
"status": "proposed",
|
||||||
|
"transaction": {
|
||||||
|
"Account": "rUPotLj5CNKaP4bQANcecEuT8hai3VpxfB",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 114177,
|
||||||
|
"Sequence": 3862,
|
||||||
|
"SigningPubKey": "FA16E9F38DF11402953A5B030C1AE8A88C47E348170C3B8EC6C8D775E797168F09",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"hash": "815AF3AC669F513C039C0AB9F31D30703343A4D39EA7AA8D26F515B56B74D728"
|
||||||
|
},
|
||||||
|
"type": "transaction",
|
||||||
|
"validated": false
|
||||||
|
}
|
||||||
44
test/fixtures/transaction.json
vendored
Normal file
44
test/fixtures/transaction.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"engine_result": "tesSUCCESS",
|
||||||
|
"engine_result_code": 0,
|
||||||
|
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||||
|
"ledger_hash": "000515A6137F4D24C111EE1FA48AE555671E7788428085D6A7492CD82A166000",
|
||||||
|
"ledger_index": 11368743,
|
||||||
|
"meta": {
|
||||||
|
"AffectedNodes": [
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Account": "rfFTrpgpm7c3pXsZMD9wnMiUDDF1UGvdcy",
|
||||||
|
"Balance": "1",
|
||||||
|
"Flags": 4849664,
|
||||||
|
"OwnerCount": 3,
|
||||||
|
"Sequence": 3860
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"LedgerIndex": "000400950EA27EB5710C0D5BE1D2B0009139F168AC5D07C13B8140EC3F82A000",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Balance": "382724563",
|
||||||
|
"Sequence": 3859
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 1,
|
||||||
|
"TransactionResult": "tesSUCCESS"
|
||||||
|
},
|
||||||
|
"status": "closed",
|
||||||
|
"transaction": {
|
||||||
|
"Account": "rfFTrpgpm7c3pXsZMD9wnMiUDDF1UGvdcy",
|
||||||
|
"Fee": "12000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 11368745,
|
||||||
|
"Sequence": 3859,
|
||||||
|
"SigningPubKey": "`123E9F38DF11402953A5B030C1AE8AE348170C3B8EC6C8D775E7971684222",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"date": 475696890,
|
||||||
|
"hash": "2D019346ED13ED8FB61F60B9F96E69B47A05B0055EB4AD5215E2072250E6CF07"
|
||||||
|
},
|
||||||
|
"type": "transaction",
|
||||||
|
"validated": true
|
||||||
|
}
|
||||||
294
test/fixtures/transactionmanager.json
vendored
Normal file
294
test/fixtures/transactionmanager.json
vendored
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
{
|
||||||
|
"ACCOUNT": {
|
||||||
|
"address": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"secret": "snoBcf899BdZP6nyaRHnSvE7qAJFP"
|
||||||
|
},
|
||||||
|
"ACCOUNT2": {
|
||||||
|
"address": "rn7GZeJpUafLAyKQ7wrU5SUCu2hpQq7S2W",
|
||||||
|
"secret": "ssThngbFXQWyJpK1mTeaNBrhHxHhp"
|
||||||
|
},
|
||||||
|
"SUBSCRIBE_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"type": "response",
|
||||||
|
"status": "success",
|
||||||
|
"result": {
|
||||||
|
"fee_base": 10,
|
||||||
|
"fee_ref": 10,
|
||||||
|
"hostid": "NBZ",
|
||||||
|
"ledger_hash": "F1AF7D977B01D99D013EEE75136263A0937575882CC9A741662C3C111B08B112",
|
||||||
|
"ledger_index": 1,
|
||||||
|
"ledger_time": 463782770,
|
||||||
|
"load_base": 256,
|
||||||
|
"load_factor": 256,
|
||||||
|
"pubkey_node": "n3Lp7DfQmxjHF5mYJsV2U9anALHmPem8PWQHWGpw4XMz79HA5aJH",
|
||||||
|
"random": "EECFEE93BBB608914F190EC177B11DE52FC1D75D2C97DACBD26D2DFC6050E874",
|
||||||
|
"reserve_base": 20000000,
|
||||||
|
"reserve_inc": 5000000,
|
||||||
|
"server_status": "full",
|
||||||
|
"validated_ledgers": "32570-11692908"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ACCOUNT_INFO_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"type": "response",
|
||||||
|
"status": "success",
|
||||||
|
"result": {
|
||||||
|
"account_data": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Balance": "10000",
|
||||||
|
"Flags": 4849664,
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"OwnerCount": 1,
|
||||||
|
"Sequence": 3,
|
||||||
|
"index": "01F3A2D58A5B986BF31CD92B513EB539CE48F705BB0E18FA39EF042DBE07A5DE"
|
||||||
|
},
|
||||||
|
"ledger_current_index": 11699032,
|
||||||
|
"validated": false
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"TX_STREAM_TRANSACTION": {
|
||||||
|
"engine_result": "tesSUCCESS",
|
||||||
|
"engine_result_code": 0,
|
||||||
|
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||||
|
"ledger_hash": "8093A78DEFD1F02037ABD349BD452081554A1DB1FE5E20DCB82D8DF16DD23B6D",
|
||||||
|
"ledger_index": 1,
|
||||||
|
"meta": {
|
||||||
|
"AffectedNodes": [
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"FinalFields": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Balance": "1000",
|
||||||
|
"Flags": 4849664,
|
||||||
|
"OwnerCount": 1,
|
||||||
|
"Sequence": 1
|
||||||
|
},
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"LedgerIndex": "A4B28FB972EF890DC39A8557DF8960D41DADA00D39B0F1EFCD4BBB85FCA13A30",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Balance": "1000",
|
||||||
|
"Sequence": 3864
|
||||||
|
},
|
||||||
|
"PreviousTxnID": "F4910E55A39C42AB82071212D84119631DDE0B0F4F8F9040F252B0066898DBDF",
|
||||||
|
"PreviousTxnLgrSeq": 11693103
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionIndex": 9,
|
||||||
|
"TransactionResult": "tesSUCCESS"
|
||||||
|
},
|
||||||
|
"status": "closed",
|
||||||
|
"transaction": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Fee": "10",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 11693114,
|
||||||
|
"Sequence": 1,
|
||||||
|
"SigningPubKey": "2D7F6A1F5F1AE2E0105A88F47D33A0B68031DE7FC43FF42388DA7D4B4C93865F",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"TxnSignature": "39A0EC2307723546901BC8017CED16DF3DD79F50CA68A32377E0CF1BE097DCA004C21D99120220321921230C53A87629D79E6A5E74C08ECB59F8CBB9D695256DE5D0F8CB22FF0A",
|
||||||
|
"date": 4771619,
|
||||||
|
"hash": "01D66ACBD00B2A8F5D66FC8F67AC879CAECF49BC94FB97CF24F66B8406F4C040"
|
||||||
|
},
|
||||||
|
"type": "transaction",
|
||||||
|
"validated": true
|
||||||
|
|
||||||
|
},
|
||||||
|
"ACCOUNT_TX_TRANSACTION": {
|
||||||
|
"validated": true,
|
||||||
|
"meta": {
|
||||||
|
"TransactionIndex": 3,
|
||||||
|
"AffectedNodes": [
|
||||||
|
{
|
||||||
|
"ModifiedNode": {
|
||||||
|
"LedgerEntryType": "AccountRoot",
|
||||||
|
"PreviousTxnLgrSeq": 11693103,
|
||||||
|
"PreviousTxnID": "F4910E55A39C42AB82071212D84119631DDE0B0F4F8F9040F252B0066898DBDF",
|
||||||
|
"LedgerIndex": "A4B28FB972EF890DC39A8557DF8960D41DADA00D39B0F1EFCD4BBB85FCA13A30",
|
||||||
|
"PreviousFields": {
|
||||||
|
"Sequence": 3864,
|
||||||
|
"Balance": "1000"
|
||||||
|
},
|
||||||
|
"FinalFields": {
|
||||||
|
"Flags": 4849664,
|
||||||
|
"Sequence": 3865,
|
||||||
|
"OwnerCount": 1,
|
||||||
|
"Balance": "1000",
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"TransactionResult": "tesSUCCESS"
|
||||||
|
},
|
||||||
|
"tx": {
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"Sequence": 3864,
|
||||||
|
"LastLedgerSequence": 2,
|
||||||
|
"Fee": "10",
|
||||||
|
"SigningPubKey": "2D7F6A1F5F1AE2E0105A88F47D33A0B68031DE7FC43FF42388DA7D4B4C93865F",
|
||||||
|
"TxnSignature": "39A0EC2307723546901BC8017CED16DF3DD79F50CA68A32377E0CF1BE097DCA004C21D99120220321921230C53A87629D79E6A5E74C08ECB59F8CBB9D695256DE5D0F8CB22FF",
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"hash": "01D66ACBD00B2A8F5D66FC8F67AC879CAECF49BC94FB97CF24F66B8406F4C040",
|
||||||
|
"ledger_index": 1,
|
||||||
|
"inLedger": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ACCOUNT_TX_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"status": "success",
|
||||||
|
"type": "response",
|
||||||
|
"result": {
|
||||||
|
"account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"ledger_index_max": 100,
|
||||||
|
"ledger_index_min": 1,
|
||||||
|
"limit": 10,
|
||||||
|
"transactions": [ ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LEDGER": {
|
||||||
|
"type": "ledgerClosed",
|
||||||
|
"fee_base": 10,
|
||||||
|
"fee_ref": 10,
|
||||||
|
"ledger_hash": "FF757ECCF710C27DBCEC569840C38C5583594B56C49693079D95D8A99C30A928",
|
||||||
|
"ledger_index": 1,
|
||||||
|
"ledger_time": 478088,
|
||||||
|
"reserve_base": 20000000,
|
||||||
|
"reserve_inc": 5000000,
|
||||||
|
"txn_count": 1,
|
||||||
|
"validated_ledgers": "1-2"
|
||||||
|
},
|
||||||
|
"ACCOUNT_TX_ERROR": {
|
||||||
|
"id": 1,
|
||||||
|
"status": "error",
|
||||||
|
"type": "response",
|
||||||
|
"error": "actMalformed",
|
||||||
|
"error_code": 33,
|
||||||
|
"error_message": "Account malformed.",
|
||||||
|
"request": {
|
||||||
|
"account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3dZ",
|
||||||
|
"binary": true,
|
||||||
|
"command": "account_tx",
|
||||||
|
"id": 1,
|
||||||
|
"ledger_index_max": -1,
|
||||||
|
"ledger_index_min": -1,
|
||||||
|
"limit": 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SUBMIT_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"result": {
|
||||||
|
"engine_result": "tesSUCCESS",
|
||||||
|
"engine_result_code": 0,
|
||||||
|
"engine_result_message": "The transaction was applied. Only final in a validated ledger.",
|
||||||
|
"tx_blob": "12000322800000002400000001201B0000000568400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC744730450221008DFE8B50D66F2094652AA6BD1B354CC97E885BC1AEDF586C7ED61C7D786AA66202200FEE38460CF25C726A7F31626BD7A45542AFB2E468EBE9A175F9A9EC3FD19DDB811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Fee": "12000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 1,
|
||||||
|
"Sequence": 1,
|
||||||
|
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"TxnSignature": "30440220332316AC7B96B1385F4BD0159706439889A9E05AD62D168E61AC5CBD7BD417C00220361D9FBC31A5919F68FA70E9FB78C6E6C25CC7F89D0A2F9CC42660594EE0D0A2",
|
||||||
|
"hash": "0D15A847D605DB5F1B76A4EE88EDCD5D279D47F009CFCE27F1D3DFE763225975"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "success",
|
||||||
|
"type": "response"
|
||||||
|
|
||||||
|
},
|
||||||
|
"SUBMIT_TEC_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"result": {
|
||||||
|
"engine_result": "tecNO_REGULAR_KEY",
|
||||||
|
"engine_result_code": 131,
|
||||||
|
"engine_result_message": "Regular key is not set.",
|
||||||
|
"tx_blob": "12000322800000002400000001201B0000000520210000000468400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC74473045022100EEB2D1EFDC4B63A3FA9BD934307D3377197E86133A156022A01FFAD7CE3A78FA022024EB39D525FE42853F8E6B62BB74124FD0A1F763C56621AA8EC6A0FC0D0A6FC0811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Fee": "12000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 2,
|
||||||
|
"Sequence": 1,
|
||||||
|
"SetFlag": 4,
|
||||||
|
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"TxnSignature": "304402202DF7ED29DCA16F7A6191A74127437ACA04ADFCE6DB570101737C6426DD664FF5022069E9C6965DED37207708420B3B77A8CE9D0D009EE1D2434580ED4871398574D0",
|
||||||
|
"hash": "56DCAE121213AA2E3A74921F934E78635DC0576E4DA1184AEE7D0F8E49046790"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "success",
|
||||||
|
"type": "response"
|
||||||
|
},
|
||||||
|
"SUBMIT_TER_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"result": {
|
||||||
|
"engine_result": "terNO_ACCOUNT",
|
||||||
|
"engine_result_code": -96,
|
||||||
|
"engine_result_message": "The source account does not exist.",
|
||||||
|
"tx_blob": "12000022800000002400000004201B0000000561400000000000000168400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC74473045022100BDEF89CF25B541FFDBBE0B652BF29D8C30715C8226346C72DBA69B275BC471C50220582C5F3DE6DE489E10594BD8911B2917EE9A452E6ED3A1BEED25E402CD2E3EFF811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C883143108B9AC27BF036EFE5CBE787921F54D622B7A5B",
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Amount": "1",
|
||||||
|
"Destination": "rn7GZeJpUafLAyKQ7wrU5SUCu2hpQq7S2W",
|
||||||
|
"Fee": "12000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 2,
|
||||||
|
"Sequence": 1,
|
||||||
|
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||||
|
"TransactionType": "Payment",
|
||||||
|
"TxnSignature": "3044022041F099FD8F35F67E73B5F41FFD3CBCF5781748BFEBA6FD1AB56586EE71B7EE9902205F1C4DF58B40859A404939B44A169DA995DA03C6ED713C5DF76E57A843CCE7D1",
|
||||||
|
"hash": "31090EA7996DFA6C2E0B43F704C30EC9AE635C18D7BEF90F42D4E0E2943A2680"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "success",
|
||||||
|
"type": "response"
|
||||||
|
},
|
||||||
|
"SUBMIT_TEF_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"result": {
|
||||||
|
"engine_result": "tefPAST_SEQ",
|
||||||
|
"engine_result_code": -189,
|
||||||
|
"engine_result_message": "This sequence number has already past.",
|
||||||
|
"tx_blob": "12000322800000002400000002201B0000000568400000000000000C732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC744730450221008B213EA1B4AACA9545E3DBFE43C69711DF295170B6F510CCD24B383684852C0702200E2A8FA3B205F1AFECF6D6DE298889D71E06336942ADF538847C8EFB88D3AA74811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Fee": "12000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 2,
|
||||||
|
"Sequence": 1,
|
||||||
|
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"TxnSignature": "304402203F6B9445B3B2176957C1008EBC0F18668464080A2CB10E78D83FB67DE2ABC3F50220769673DE79E6C1AF0E076A716ABE53018158385615E7EC2866DCFD6268806BF8",
|
||||||
|
"hash": "731E94632E219ECAF2043C09C0075F1DEA2EC08E66A381CD536F0B1F3B30844D"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "success",
|
||||||
|
"type": "response"
|
||||||
|
},
|
||||||
|
"SUBMIT_TEL_RESPONSE": {
|
||||||
|
"id": 1,
|
||||||
|
"result": {
|
||||||
|
"engine_result": "telINSUF_FEE_P",
|
||||||
|
"engine_result_code": -394,
|
||||||
|
"engine_result_message": "Fee insufficient.",
|
||||||
|
"tx_blob": "12000322800000002400000003201B00000005684000000000000001732102999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC7446304402206480AC2410BE4370E74E27B4427EF05F8A156D313C9D768E57B6EEC3BB89CDD402201503759955F367F88E5442F08D713B5369C5528475F046500721E676C24D0DFD811492DECA2DC92352BE97C1F6347F7E6CCB9A8241C8",
|
||||||
|
"tx_json": {
|
||||||
|
"Account": "rNP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d",
|
||||||
|
"Fee": "12000",
|
||||||
|
"Flags": 2147483648,
|
||||||
|
"LastLedgerSequence": 2,
|
||||||
|
"Sequence": 1,
|
||||||
|
"SigningPubKey": "02999FB4BC17144F83CDC2F17EA642519FF115EE7B0CC8C78DE9061F1A473F7BAC",
|
||||||
|
"TransactionType": "AccountSet",
|
||||||
|
"TxnSignature": "3044022002C0C13B21F9B690C6A3FF4B5A3F966AC47ACEE80453DAD553F5051FB3CED0E902202851BCC9EF8E2160BD1F3F6CF91B7C679149BD5FAD502C2BA544F7E61755AD1B",
|
||||||
|
"hash": "ABF970193B8C9BE9BBD2777750924B28E7542DE1491EB55F4795539045AEA8B9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": "success",
|
||||||
|
"type": "response"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var Seed = require('ripple-lib').Seed;
|
||||||
var Seed = utils.load_module('seed').Seed;
|
|
||||||
var config = require('./testutils').get_config();
|
|
||||||
|
|
||||||
describe('KeyPair', function() {
|
describe('KeyPair', function() {
|
||||||
it('can generate an address', function () {
|
it('can generate an address', function () {
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
var utils = require('./testutils');
|
var Ledger = require('ripple-lib').Ledger;
|
||||||
var Ledger = utils.load_module('ledger').Ledger;
|
|
||||||
var config = require('./testutils').get_config();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ledger_index {Number}
|
* @param ledger_index {Number}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var sjcl = require('../build/sjcl');
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
var Message = require('../src/js/ripple/message').Message;
|
var Message = require('ripple-lib').Message;
|
||||||
var Seed = require('../src/js/ripple/seed').Seed;
|
var Seed = require('ripple-lib').Seed;
|
||||||
var Remote = require('../src/js/ripple/remote').Remote;
|
var Remote = require('ripple-lib').Remote;
|
||||||
|
|
||||||
describe('Message', function(){
|
describe('Message', function(){
|
||||||
|
|
||||||
|
|||||||
36
test/metadata-test.js
Normal file
36
test/metadata-test.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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/
|
||||||
File diff suppressed because it is too large
Load Diff
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, [ ]);
|
||||||
|
});
|
||||||
|
});
|
||||||
1749
test/remote-test.js
1749
test/remote-test.js
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var Request = require('ripple-lib').Request;
|
||||||
var Request = utils.load_module('request').Request;
|
var Remote = require('ripple-lib').Remote;
|
||||||
var Remote = utils.load_module('remote').Remote;
|
var Server = require('ripple-lib').Server;
|
||||||
var Server = utils.load_module('server').Server;
|
var Currency = require('ripple-lib').Currency;
|
||||||
var Currency = utils.load_module('currency').Currency;
|
var RippleError = require('ripple-lib').RippleError;
|
||||||
|
|
||||||
function makeServer(url) {
|
function makeServer(url) {
|
||||||
var server = new Server(new process.EventEmitter(), url);
|
var server = new Server(new process.EventEmitter(), url);
|
||||||
@@ -56,7 +56,7 @@ describe('Request', function() {
|
|||||||
request.request();
|
request.request();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Broadcast request', function(done) {
|
it('Send request -- filterRequest', function(done) {
|
||||||
var servers = [
|
var servers = [
|
||||||
makeServer('wss://localhost:5006'),
|
makeServer('wss://localhost:5006'),
|
||||||
makeServer('wss://localhost:5007')
|
makeServer('wss://localhost:5007')
|
||||||
@@ -64,24 +64,401 @@ describe('Request', function() {
|
|||||||
|
|
||||||
var requests = 0;
|
var requests = 0;
|
||||||
|
|
||||||
servers.forEach(function(server, index, arr) {
|
var successResponse = {
|
||||||
server._request = function(req) {
|
account_data: {
|
||||||
assert(req instanceof Request);
|
Account: 'rnoFoLJmqmXe7a7iswk19yfdMHQkbQNrKC',
|
||||||
assert.strictEqual(typeof req.message, 'object');
|
Balance: '13188802787',
|
||||||
assert.strictEqual(req.message.command, 'server_info');
|
Flags: 0,
|
||||||
if (++requests === arr.length) {
|
LedgerEntryType: 'AccountRoot',
|
||||||
done();
|
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();
|
var remote = new Remote();
|
||||||
remote._connected = true;
|
remote._connected = true;
|
||||||
remote._servers = servers;
|
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) {
|
it('Events API', function(done) {
|
||||||
@@ -349,6 +726,16 @@ describe('Request', function() {
|
|||||||
assert.strictEqual(request.message.ledger_hash, void(0));
|
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() {
|
it('Select ledger - hash', function() {
|
||||||
var remote = new Remote();
|
var remote = new Remote();
|
||||||
remote._connected = true;
|
remote._connected = true;
|
||||||
|
|||||||
@@ -1,29 +1,7 @@
|
|||||||
|
/* eslint max-len: 0 */
|
||||||
|
'use strict';
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var Seed = require('ripple-lib').Seed;
|
||||||
var Seed = utils.load_module('seed').Seed;
|
|
||||||
var config = require('./testutils').get_config();
|
|
||||||
|
|
||||||
describe('Seed', function() {
|
|
||||||
it('can generate many addresses', function () {
|
|
||||||
|
|
||||||
var test_data = [
|
|
||||||
// Format:
|
|
||||||
// [passphrase, address, nth-for-seed, expected-public-key]
|
|
||||||
["masterpassphrase", "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", 0,
|
|
||||||
"0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020"],
|
|
||||||
["masterpassphrase", "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP", 1,
|
|
||||||
"02CD8C4CE87F86AAD1D9D18B03DE28E6E756F040BD72A9C127862833EB90D60BAD"],
|
|
||||||
["masterpassphrase", "rLpAd4peHUMBPbVJASMYK5GTBUSwXRD9nx", 2,
|
|
||||||
"0259A57642A6F4AEFC9B8062AF453FDEEEAC5572BA602BB1DBD5EF011394C6F9FC"],
|
|
||||||
["otherpassphrase", "rpe3YWSVwGU2PmUzebAPg2deBXHtmba7hJ", 0,
|
|
||||||
"022235A3DB2CAE57C60B7831929611D58867F86D28C0AD3C82473CC4A84990D01B"],
|
|
||||||
["otherpassphrase", "raAPC2gALSmsTkXR4wUwQcPgX66kJuLv2S", 5,
|
|
||||||
"03F0619AFABE08D22D98C8721895FE3673B6174168949976F2573CE1138C124994"],
|
|
||||||
["yetanotherpassphrase", "rKnM44fS48qrGiDxB5fB5u64vHVJwjDPUo", 0,
|
|
||||||
"0385AD049327EF7E5EC429350A15CEB23955037DE99660F6E70C11C5ABF4407036"],
|
|
||||||
["yetanotherpassphrase", "rMvkT1RHPfsZwTFbKDKBEisa5U4d2a9V8n", 1,
|
|
||||||
"023A2876EA130CBE7BBA0573C2DB4C4CEB9A7547666915BD40366CDC6150CF54DC"]
|
|
||||||
];
|
|
||||||
|
|
||||||
function assert_helper(seed_json, address_or_nth, expected) {
|
function assert_helper(seed_json, address_or_nth, expected) {
|
||||||
var seed = Seed.from_json(seed_json);
|
var seed = Seed.from_json(seed_json);
|
||||||
@@ -31,6 +9,36 @@ describe('Seed', function() {
|
|||||||
assert.strictEqual(keypair.to_hex_pub(), expected);
|
assert.strictEqual(keypair.to_hex_pub(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe('Seed', function() {
|
||||||
|
it('saESc82Vun7Ta5EJRzGJbrXb5HNYk', function () {
|
||||||
|
var seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
|
||||||
|
assert.strictEqual(seed.to_hex(), 'FF1CF838D02B2CF7B45BAC27F5F24F4F');
|
||||||
|
});
|
||||||
|
it('sp6iDHnmiPN7tQFHm5sCW59ax3hfE', function () {
|
||||||
|
var seed = Seed.from_json('sp6iDHnmiPN7tQFHm5sCW59ax3hfE');
|
||||||
|
assert.strictEqual(seed.to_hex(), '00AD8DA764C3C8AF5F9B8D51C94B9E49');
|
||||||
|
});
|
||||||
|
it('can generate many addresses', function () {
|
||||||
|
|
||||||
|
var test_data = [
|
||||||
|
// Format:
|
||||||
|
// [passphrase, address, nth-for-seed, expected-public-key]
|
||||||
|
['masterpassphrase', 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', 0,
|
||||||
|
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020'],
|
||||||
|
['masterpassphrase', 'r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP', 1,
|
||||||
|
'02CD8C4CE87F86AAD1D9D18B03DE28E6E756F040BD72A9C127862833EB90D60BAD'],
|
||||||
|
['masterpassphrase', 'rLpAd4peHUMBPbVJASMYK5GTBUSwXRD9nx', 2,
|
||||||
|
'0259A57642A6F4AEFC9B8062AF453FDEEEAC5572BA602BB1DBD5EF011394C6F9FC'],
|
||||||
|
['otherpassphrase', 'rpe3YWSVwGU2PmUzebAPg2deBXHtmba7hJ', 0,
|
||||||
|
'022235A3DB2CAE57C60B7831929611D58867F86D28C0AD3C82473CC4A84990D01B'],
|
||||||
|
['otherpassphrase', 'raAPC2gALSmsTkXR4wUwQcPgX66kJuLv2S', 5,
|
||||||
|
'03F0619AFABE08D22D98C8721895FE3673B6174168949976F2573CE1138C124994'],
|
||||||
|
['yetanotherpassphrase', 'rKnM44fS48qrGiDxB5fB5u64vHVJwjDPUo', 0,
|
||||||
|
'0385AD049327EF7E5EC429350A15CEB23955037DE99660F6E70C11C5ABF4407036'],
|
||||||
|
['yetanotherpassphrase', 'rMvkT1RHPfsZwTFbKDKBEisa5U4d2a9V8n', 1,
|
||||||
|
'023A2876EA130CBE7BBA0573C2DB4C4CEB9A7547666915BD40366CDC6150CF54DC']
|
||||||
|
];
|
||||||
|
|
||||||
for (var nth = 0; nth < test_data.length; nth++) {
|
for (var nth = 0; nth < test_data.length; nth++) {
|
||||||
var seed_json = test_data[nth][0];
|
var seed_json = test_data[nth][0];
|
||||||
var address = test_data[nth][1];
|
var address = test_data[nth][1];
|
||||||
@@ -45,7 +53,7 @@ describe('Seed', function() {
|
|||||||
|
|
||||||
// This isn't too bad as it only needs to generate one keypair `seq`
|
// This isn't too bad as it only needs to generate one keypair `seq`
|
||||||
assert_helper(seed_json, nth_for_seed, expected);
|
assert_helper(seed_json, nth_for_seed, expected);
|
||||||
};
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
var utils = require('./testutils');
|
'use strict';
|
||||||
|
|
||||||
|
/* eslint-disable max-len*/
|
||||||
|
/* eslint-disable key-spacing*/
|
||||||
|
/* eslint-disable no-spaced-func*/
|
||||||
|
/* eslint-disable space-before-blocks*/
|
||||||
|
/* eslint-disable space-unary-ops*/
|
||||||
|
/* eslint-disable no-multi-spaces*/
|
||||||
|
/* eslint-disable no-void*/
|
||||||
|
/* eslint-disable semi*/
|
||||||
|
/* eslint-disable no-unused-vars*/
|
||||||
|
/* eslint-disable quotes*/
|
||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var SerializedObject = utils.load_module('serializedobject').SerializedObject;
|
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||||
var sjcl = require('./../src/js/ripple/utils').sjcl;
|
var Amount = require('ripple-lib').Amount;
|
||||||
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
|
|
||||||
// Shortcuts
|
// Shortcuts
|
||||||
var hex = sjcl.codec.hex;
|
var hex = sjcl.codec.hex;
|
||||||
@@ -30,10 +43,14 @@ describe('Serialized object', function() {
|
|||||||
{
|
{
|
||||||
account: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
account: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV'
|
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
|
||||||
|
type: 49,
|
||||||
|
type_hex: "0000000000000031"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
currency: 'XRP'
|
currency: 'XRP',
|
||||||
|
type: 16,
|
||||||
|
type_hex: "0000000000000010"
|
||||||
}
|
}
|
||||||
]],
|
]],
|
||||||
SendMax: {
|
SendMax: {
|
||||||
@@ -51,6 +68,56 @@ describe('Serialized object', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#from_json(v).to_json() == v -- invalid amount', function(){
|
||||||
|
it('outputs same as passed to from_json', function() {
|
||||||
|
var input_json = {
|
||||||
|
Account: 'rUR9gTCcrUY9fMkz9rwcM9urPREh3LKXoW',
|
||||||
|
Fee: '10',
|
||||||
|
Flags: 0,
|
||||||
|
Sequence: 65,
|
||||||
|
SigningPubKey: '033D0B1FB932E0408C119107483190B61561DCE8529E29CB5D1C69128DA54DA715',
|
||||||
|
TakerGets: '2188313981504612096',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'r9rp9MUFRJVCVLRm3MTmUvSPNBSL3BuEFx',
|
||||||
|
value: '99999999999'
|
||||||
|
},
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
TxnSignature: '304602210085C6AE945643150E6D450CF796E45D74FB24B4E03E964A29CC6AFFEB346C77C80221009BE1B6678CF6C2E61F8F2696144C75AFAF66DF4FC0733DF9118EDEFEEFE33243'
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.throws(function() {
|
||||||
|
SerializedObject.from_json(input_json).to_json();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#from_json(v).to_json() == v -- invalid amount, strict_mode = false', function(){
|
||||||
|
it('outputs same as passed to from_json', function() {
|
||||||
|
var input_json = {
|
||||||
|
Account: 'rUR9gTCcrUY9fMkz9rwcM9urPREh3LKXoW',
|
||||||
|
Fee: '10',
|
||||||
|
Flags: 0,
|
||||||
|
Sequence: 65,
|
||||||
|
SigningPubKey: '033D0B1FB932E0408C119107483190B61561DCE8529E29CB5D1C69128DA54DA715',
|
||||||
|
TakerGets: '2188313981504612096',
|
||||||
|
TakerPays: {
|
||||||
|
currency: 'USD',
|
||||||
|
issuer: 'r9rp9MUFRJVCVLRm3MTmUvSPNBSL3BuEFx',
|
||||||
|
value: '99999999999'
|
||||||
|
},
|
||||||
|
TransactionType: 'OfferCreate',
|
||||||
|
TxnSignature: 'FFFFFF210085C6AE945643150E6D450CF796E45D74FB24B4E03E964A29CC6AFFEB346C77C80221009BE1B6678CF6C2E61F8F2696144C75AFAF66DF4FC0733DF9118EDEFEEFE33243'
|
||||||
|
};
|
||||||
|
|
||||||
|
var strictMode = Amount.strict_mode;
|
||||||
|
Amount.strict_mode = false;
|
||||||
|
var output_json = SerializedObject.from_json(input_json).to_json();
|
||||||
|
assert.deepEqual(input_json, output_json);
|
||||||
|
Amount.strict_mode = strictMode;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#from_json', function() {
|
describe('#from_json', function() {
|
||||||
it('understands TransactionType as a Number', function() {
|
it('understands TransactionType as a Number', function() {
|
||||||
var input_json = {
|
var input_json = {
|
||||||
@@ -106,7 +173,6 @@ describe('Serialized object', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Memos', function() {
|
describe('Memos', function() {
|
||||||
|
|
||||||
var input_json;
|
var input_json;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
@@ -127,10 +193,10 @@ describe('Serialized object', function() {
|
|||||||
it('should serialize and parse - full memo, all strings text/plain ', function() {
|
it('should serialize and parse - full memo, all strings text/plain ', function() {
|
||||||
input_json.Memos = [
|
input_json.Memos = [
|
||||||
{
|
{
|
||||||
"Memo": {
|
Memo: {
|
||||||
"MemoType": "test",
|
MemoType: '74657374',
|
||||||
"MemoFormat": "text",
|
MemoFormat: '74657874',
|
||||||
"MemoData": "some data"
|
MemoData: '736F6D652064617461'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -149,10 +215,11 @@ describe('Serialized object', function() {
|
|||||||
it('should serialize and parse - full memo, all strings, invalid MemoFormat', function() {
|
it('should serialize and parse - full memo, all strings, invalid MemoFormat', function() {
|
||||||
input_json.Memos = [
|
input_json.Memos = [
|
||||||
{
|
{
|
||||||
"Memo": {
|
"Memo":
|
||||||
"MemoType": "test",
|
{
|
||||||
"MemoFormat": "application/json",
|
MemoType: '74657374',
|
||||||
"MemoData": "some data"
|
MemoFormat: '6170706C69636174696F6E2F6A736F6E',
|
||||||
|
MemoData: '736F6D652064617461'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -168,36 +235,14 @@ describe('Serialized object', function() {
|
|||||||
assert.strictEqual(input_json.Memos[0].Memo.parsed_memo_data, void(0));
|
assert.strictEqual(input_json.Memos[0].Memo.parsed_memo_data, void(0));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error - full memo, json data, invalid MemoFormat', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
"Memo": {
|
|
||||||
"MemoType": "test",
|
|
||||||
"MemoFormat": "text",
|
|
||||||
"MemoData": {
|
|
||||||
"string" : "some_string",
|
|
||||||
"boolean" : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
assert.throws(function() {
|
|
||||||
SerializedObject.from_json(input_json);
|
|
||||||
}, /^Error: MemoData can only be a JSON object with a valid json MemoFormat \(Memo\) \(Memos\)/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should serialize and parse - full memo, json data, valid MemoFormat, ignored field', function() {
|
it('should serialize and parse - full memo, json data, valid MemoFormat, ignored field', function() {
|
||||||
input_json.Memos = [
|
input_json.Memos = [
|
||||||
{
|
{
|
||||||
"Memo": {
|
Memo: {
|
||||||
"MemoType": "test",
|
MemoType: '74657374',
|
||||||
"MemoFormat": "json",
|
MemoFormat: '6A736F6E',
|
||||||
"ignored" : "ignored",
|
ignored : 'ignored',
|
||||||
"MemoData": {
|
MemoData: '7B22737472696E67223A22736F6D655F737472696E67222C22626F6F6C65616E223A747275657D'
|
||||||
"string" : "some_string",
|
|
||||||
"boolean" : true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -222,79 +267,25 @@ describe('Serialized object', function() {
|
|||||||
assert.deepEqual(so, input_json);
|
assert.deepEqual(so, input_json);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should serialize and parse - full memo, json data, valid MemoFormat', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
"Memo": {
|
|
||||||
"MemoType": "test",
|
|
||||||
"MemoFormat": "json",
|
|
||||||
"MemoData": {
|
|
||||||
"string" : "some_string",
|
|
||||||
"boolean" : true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var so = SerializedObject.from_json(input_json).to_json();
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_format = 'json';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_data = {
|
|
||||||
"string" : "some_string",
|
|
||||||
"boolean" : true
|
|
||||||
};
|
|
||||||
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
|
||||||
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('json');
|
|
||||||
input_json.Memos[0].Memo.MemoData = convertStringToHex(JSON.stringify(
|
|
||||||
{
|
|
||||||
"string" : "some_string",
|
|
||||||
"boolean" : true
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
assert.deepEqual(so, input_json);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should serialize and parse - full memo, json data, valid MemoFormat, integer', function() {
|
|
||||||
input_json.Memos = [
|
|
||||||
{
|
|
||||||
"Memo": {
|
|
||||||
"MemoType": "test",
|
|
||||||
"MemoFormat": "json",
|
|
||||||
"MemoData": 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
var so = SerializedObject.from_json(input_json).to_json();
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_type = 'test';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_format = 'json';
|
|
||||||
input_json.Memos[0].Memo.parsed_memo_data = 3;
|
|
||||||
input_json.Memos[0].Memo.MemoType = convertStringToHex('test');
|
|
||||||
input_json.Memos[0].Memo.MemoFormat = convertStringToHex('json');
|
|
||||||
input_json.Memos[0].Memo.MemoData = convertStringToHex(JSON.parse(3));
|
|
||||||
assert.deepEqual(so, input_json);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error - invalid Memo field', function() {
|
it('should throw an error - invalid Memo field', function() {
|
||||||
input_json.Memos = [
|
input_json.Memos = [
|
||||||
{
|
{
|
||||||
"Memo": {
|
Memo: {
|
||||||
"MemoType": "test",
|
MemoType: '74657374',
|
||||||
"MemoParty": "json",
|
MemoField: '6A736F6E',
|
||||||
"MemoData": 3
|
MemoData: '7B22737472696E67223A22736F6D655F737472696E67222C22626F6F6C65616E223A747275657D'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
SerializedObject.from_json(input_json);
|
SerializedObject.from_json(input_json);
|
||||||
}, /^Error: JSON contains unknown field: "MemoParty" \(Memo\) \(Memos\)/);
|
}, /^Error: JSON contains unknown field: "MemoField" \(Memo\) \(Memos\)/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should serialize json with memo - match hex output', function() {
|
it('should serialize json with memo - match hex output', function() {
|
||||||
var input_json = {
|
input_json = {
|
||||||
Flags: 2147483648,
|
Flags: 2147483648,
|
||||||
TransactionType: 'Payment',
|
TransactionType: 'Payment',
|
||||||
Account: 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
|
Account: 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
|
||||||
@@ -303,7 +294,7 @@ describe('Serialized object', function() {
|
|||||||
Memos: [
|
Memos: [
|
||||||
{
|
{
|
||||||
Memo: {
|
Memo: {
|
||||||
MemoType: 'image'
|
MemoType: '696D616765'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
var utils = require('./testutils');
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var SerializedObject = utils.load_module('serializedobject').SerializedObject;
|
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||||
var types = utils.load_module('serializedtypes');
|
var types = require('ripple-lib').types;
|
||||||
var amountConstants = require('../src/js/ripple/amount').consts;
|
var Amount = require('ripple-lib').Amount;
|
||||||
var BigInteger = require('../src/js/jsbn/jsbn').BigInteger;
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
|
|
||||||
var config = require('./testutils').get_config();
|
|
||||||
|
|
||||||
describe('Serialized types', function() {
|
describe('Serialized types', function() {
|
||||||
describe('Int8', function() {
|
describe('Int8', function() {
|
||||||
@@ -290,7 +287,7 @@ describe('Serialized types', function() {
|
|||||||
var so = new SerializedObject("8B2386F26F8E232B");
|
var so = new SerializedObject("8B2386F26F8E232B");
|
||||||
var num = types.Int64.parse(so);
|
var num = types.Int64.parse(so);
|
||||||
// We get a positive number
|
// We get a positive number
|
||||||
assert.strictEqual(num.toString(16), '8b2386f26f8e232b');
|
assert.strictEqual(num.toString(), '0x8b2386f26f8e232b');
|
||||||
});
|
});
|
||||||
it('Serialize "0123456789ABCDEF"', function () {
|
it('Serialize "0123456789ABCDEF"', function () {
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
@@ -302,15 +299,15 @@ describe('Serialized types', function() {
|
|||||||
types.Int64.serialize(so, 'F0E1D2C3B4A59687');
|
types.Int64.serialize(so, 'F0E1D2C3B4A59687');
|
||||||
assert.strictEqual(so.to_hex(), 'F0E1D2C3B4A59687');
|
assert.strictEqual(so.to_hex(), 'F0E1D2C3B4A59687');
|
||||||
});
|
});
|
||||||
it('Serialize BigInteger("FFEEDDCCBBAA9988")', function () {
|
it('Serialize bn("FFEEDDCCBBAA9988")', function () {
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
types.Int64.serialize(so, new BigInteger('FFEEDDCCBBAA9988', 16));
|
types.Int64.serialize(so, new sjcl.bn('FFEEDDCCBBAA9988', 16));
|
||||||
assert.strictEqual(so.to_hex(), 'FFEEDDCCBBAA9988');
|
assert.strictEqual(so.to_hex(), 'FFEEDDCCBBAA9988');
|
||||||
});
|
});
|
||||||
it('Fail to serialize BigInteger("-1")', function () {
|
it('Fail to serialize BigNumber("-1")', function () {
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
types.Int64.serialize(so, new BigInteger('-1', 10));
|
types.Int64.serialize(so, new BigNumber('-1', 10));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('Fail to serialize "10000000000000000"', function () {
|
it('Fail to serialize "10000000000000000"', function () {
|
||||||
@@ -346,7 +343,7 @@ describe('Serialized types', function() {
|
|||||||
it('Parse "0123456789ABCDEF"', function () {
|
it('Parse "0123456789ABCDEF"', function () {
|
||||||
var so = new SerializedObject("0123456789ABCDEF");
|
var so = new SerializedObject("0123456789ABCDEF");
|
||||||
var num = types.Int64.parse(so);
|
var num = types.Int64.parse(so);
|
||||||
assert.strictEqual(num.toString(10), '81985529216486895');
|
assert.strictEqual(num.toString(), '0x123456789abcdef');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -512,8 +509,10 @@ describe('Serialized types', function() {
|
|||||||
});
|
});
|
||||||
it('Serialize 1161981756646125568 XRP', function () {
|
it('Serialize 1161981756646125568 XRP', function () {
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
types.Amount.serialize(so, '1161981756646125696');
|
assert.throws(function() {
|
||||||
assert.strictEqual(so.to_hex(), '5020304050607080');
|
var amt = Amount.from_json('1161981756646125696');
|
||||||
|
types.Amount.serialize(so, amt);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('Serialize 1/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
it('Serialize 1/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||||
var so = new SerializedObject();
|
var so = new SerializedObject();
|
||||||
@@ -553,7 +552,7 @@ describe('Serialized types', function() {
|
|||||||
});
|
});
|
||||||
it('Serialize max_value/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
it('Serialize max_value/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||||
var so = new SerializedObject();
|
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');
|
assert.strictEqual(so.to_hex(), 'EC6386F26FC0FFFF0000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
|
||||||
});
|
});
|
||||||
it('Parse 1 XRP', function () {
|
it('Parse 1 XRP', function () {
|
||||||
@@ -573,8 +572,11 @@ describe('Serialized types', function() {
|
|||||||
assert.strictEqual(types.Amount.parse(so).to_json(), '270544960');
|
assert.strictEqual(types.Amount.parse(so).to_json(), '270544960');
|
||||||
});
|
});
|
||||||
it('Parse 1161981756646125568 XRP', function () {
|
it('Parse 1161981756646125568 XRP', function () {
|
||||||
var so = new SerializedObject('5020304050607080');
|
assert.throws(function() {
|
||||||
assert.strictEqual(types.Amount.parse(so).to_json(), '1161981756646125696');
|
// hex(1161981756646125568) = 1020304050607000
|
||||||
|
var so = new SerializedObject('1020304050607000');
|
||||||
|
types.Amount.parse(so).to_json();
|
||||||
|
})
|
||||||
});
|
});
|
||||||
it('Parse 1/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
it('Parse 1/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||||
var so = new SerializedObject('D4838D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
|
var so = new SerializedObject('D4838D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
|
||||||
@@ -590,7 +592,7 @@ describe('Serialized types', function() {
|
|||||||
});
|
});
|
||||||
it('Parse max_value/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
it('Parse max_value/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
|
||||||
var so = new SerializedObject('EC6386F26FC0FFFF0000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
|
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');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -690,13 +692,34 @@ 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();
|
var so = new SerializedObject();
|
||||||
types.PathSet.serialize(so, json);
|
types.PathSet.serialize(so, json);
|
||||||
assert.strictEqual(so.to_hex(), hex);
|
assert.strictEqual(so.to_hex(), hex);
|
||||||
|
|
||||||
so = new SerializedObject(hex);
|
so = new SerializedObject(hex);
|
||||||
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
|
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 () {
|
it('Serialize path through XRP IOUs', function () {
|
||||||
var hex = '31000000000000000000000000000000000000007B00000000000000000000000055534400000000000000000000000000000000000000000000000315FF1000000000000000000000000058525000000000003100000000000000000000000000000000000003DB0000000000000000000000004555520000000000000000000000000000000000000000000000014100';
|
var hex = '31000000000000000000000000000000000000007B00000000000000000000000055534400000000000000000000000000000000000000000000000315FF1000000000000000000000000058525000000000003100000000000000000000000000000000000003DB0000000000000000000000004555520000000000000000000000000000000000000000000000014100';
|
||||||
@@ -716,13 +739,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();
|
var so = new SerializedObject();
|
||||||
types.PathSet.serialize(so, json);
|
types.PathSet.serialize(so, json);
|
||||||
assert.strictEqual(so.to_hex(), hex);
|
assert.strictEqual(so.to_hex(), hex);
|
||||||
|
|
||||||
so = new SerializedObject(hex);
|
so = new SerializedObject(hex);
|
||||||
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
|
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 () {
|
it('Serialize path through XRP IOUs (realistic example)', function () {
|
||||||
// Appears in the history
|
// Appears in the history
|
||||||
@@ -781,13 +826,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();
|
var so = new SerializedObject();
|
||||||
types.PathSet.serialize(so, json);
|
types.PathSet.serialize(so, json);
|
||||||
assert.strictEqual(so.to_hex(), hex);
|
assert.strictEqual(so.to_hex(), hex);
|
||||||
|
|
||||||
so = new SerializedObject(hex);
|
so = new SerializedObject(hex);
|
||||||
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
|
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 () {
|
it('Parse single empty path [[]]', function () {
|
||||||
var so = new SerializedObject('00');
|
var so = new SerializedObject('00');
|
||||||
@@ -800,13 +919,20 @@ describe('Serialized types', function() {
|
|||||||
var parsed_path = types.PathSet.parse(so);
|
var parsed_path = types.PathSet.parse(so);
|
||||||
var comp = [ [ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
var comp = [ [ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf' } ],
|
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
|
||||||
|
type: 49,
|
||||||
|
type_hex: '0000000000000031' } ],
|
||||||
[ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
[ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
|
||||||
currency: 'BTC',
|
currency: 'BTC',
|
||||||
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf' },
|
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
|
||||||
|
type: 49,
|
||||||
|
type_hex: '0000000000000031' },
|
||||||
{ account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
|
{ account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
|
||||||
currency: 'EUR',
|
currency: 'EUR',
|
||||||
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2' } ] ];
|
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2',
|
||||||
|
type: 49,
|
||||||
|
type_hex: '0000000000000031' } ] ];
|
||||||
|
|
||||||
assert.deepEqual(SerializedObject.jsonify_structure(parsed_path, ""), comp);
|
assert.deepEqual(SerializedObject.jsonify_structure(parsed_path, ""), comp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var ws = require('ws');
|
var ws = require('ws');
|
||||||
var utils = require('./testutils');
|
var Remote = require('ripple-lib').Remote;
|
||||||
var Remote = utils.load_module('remote').Remote;
|
var Server = require('ripple-lib').Server;
|
||||||
var Server = utils.load_module('server').Server;
|
var Request = require('ripple-lib').Request;
|
||||||
var Request = utils.load_module('request').Request;
|
var Transaction = require('ripple-lib').Transaction;
|
||||||
var Transaction = utils.load_module('transaction').Transaction;
|
|
||||||
|
|
||||||
describe('Server', function() {
|
describe('Server', function() {
|
||||||
it('Server constructor - invalid options', function() {
|
it('Server constructor - invalid options', function() {
|
||||||
@@ -379,8 +378,6 @@ describe('Server', function() {
|
|||||||
validated_ledgers: '32570-7053695'
|
validated_ledgers: '32570-7053695'
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
wss.close();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -388,6 +385,7 @@ describe('Server', function() {
|
|||||||
|
|
||||||
server.once('connect', function() {
|
server.once('connect', function() {
|
||||||
server.once('disconnect', function() {
|
server.once('disconnect', function() {
|
||||||
|
wss.close();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
server.disconnect();
|
server.disconnect();
|
||||||
@@ -443,8 +441,6 @@ describe('Server', function() {
|
|||||||
validated_ledgers: '32570-7053695'
|
validated_ledgers: '32570-7053695'
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
wss.close();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -452,6 +448,7 @@ describe('Server', function() {
|
|||||||
|
|
||||||
server.once('connect', function() {
|
server.once('connect', function() {
|
||||||
server.once('disconnect', function() {
|
server.once('disconnect', function() {
|
||||||
|
wss.close();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
server.disconnect();
|
server.disconnect();
|
||||||
@@ -510,15 +507,16 @@ describe('Server', function() {
|
|||||||
validated_ledgers: '3175520-3176615'
|
validated_ledgers: '3175520-3176615'
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
wss.close();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var server = new Server(new Remote({ allow_partial_history: false }), 'ws://localhost:5748');
|
var server = new Server(new Remote({
|
||||||
|
allow_partial_history: false
|
||||||
|
}), 'ws://localhost:5748');
|
||||||
|
|
||||||
server.reconnect = function() {
|
server.reconnect = function() {
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
|
wss.close();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -555,8 +553,6 @@ describe('Server', function() {
|
|||||||
server_status: 'syncing'
|
server_status: 'syncing'
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
wss.close();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -568,6 +564,7 @@ describe('Server', function() {
|
|||||||
assert.strictEqual(server._load_factor, 256);
|
assert.strictEqual(server._load_factor, 256);
|
||||||
assert.strictEqual(server._fee_base, 10);
|
assert.strictEqual(server._fee_base, 10);
|
||||||
assert.strictEqual(server._fee_ref, 10);
|
assert.strictEqual(server._fee_ref, 10);
|
||||||
|
wss.close();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1103,12 +1100,15 @@ describe('Server', function() {
|
|||||||
case 'subscribe':
|
case 'subscribe':
|
||||||
assert.strictEqual(m.command, 'subscribe');
|
assert.strictEqual(m.command, 'subscribe');
|
||||||
assert.deepEqual(m.streams, [ 'ledger', 'server' ]);
|
assert.deepEqual(m.streams, [ 'ledger', 'server' ]);
|
||||||
|
setImmediate(function() {
|
||||||
sendSubscribe(m);
|
sendSubscribe(m);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case 'server_info':
|
case 'server_info':
|
||||||
assert.strictEqual(m.command, 'server_info');
|
assert.strictEqual(m.command, 'server_info');
|
||||||
|
setImmediate(function() {
|
||||||
sendServerInfo(m);
|
sendServerInfo(m);
|
||||||
wss.close();
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1117,17 +1117,84 @@ describe('Server', function() {
|
|||||||
var server = new Server(new Remote(), 'ws://localhost:5748');
|
var server = new Server(new Remote(), 'ws://localhost:5748');
|
||||||
|
|
||||||
server.once('connect', function() {
|
server.once('connect', function() {
|
||||||
var receivedSubscribe = false;
|
|
||||||
|
|
||||||
server.once('response_server_info', function() {
|
server.once('response_server_info', function() {
|
||||||
receivedSubscribe = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
server.once('disconnect', function() {
|
|
||||||
assert(receivedSubscribe);
|
|
||||||
assert.strictEqual(server.getServerID(), 'ws://localhost:5748 (n94pSqypSfddzAVj9qoezHyUoetsrMnwgNuBqRJ3WHvM8aMMf7rW)');
|
assert.strictEqual(server.getServerID(), 'ws://localhost:5748 (n94pSqypSfddzAVj9qoezHyUoetsrMnwgNuBqRJ3WHvM8aMMf7rW)');
|
||||||
|
server.once('disconnect', function() {
|
||||||
|
wss.close();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
server.disconnect();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
server.connect();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var Seed = require('ripple-lib').Seed;
|
||||||
var Seed = utils.load_module('seed').Seed;
|
|
||||||
|
|
||||||
function _isNaN(n) {
|
function _isNaN(n) {
|
||||||
return typeof n === 'number' && isNaN(n);
|
return typeof n === 'number' && isNaN(n);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
var sjcl = require('../build/sjcl');
|
var Seed = require('ripple-lib').Seed;
|
||||||
var Seed = require('../src/js/ripple/seed').Seed;
|
|
||||||
|
|
||||||
describe('SJCL ECDSA Canonicalization', function() {
|
describe('SJCL ECDSA Canonicalization', function() {
|
||||||
describe('canonicalizeSignature', function() {
|
describe('canonicalizeSignature', function() {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
var sjcl = require('../build/sjcl');
|
|
||||||
|
|
||||||
describe('ECDSA signing with recoverable public key', function(){
|
describe('ECDSA signing with recoverable public key', function(){
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
var sjcl = require('../build/sjcl');
|
|
||||||
|
|
||||||
describe('SJCL Extramath', function() {
|
describe('SJCL Extramath', function() {
|
||||||
describe('setBitM', function() {
|
describe('setBitM', function() {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
var sjcl = require('../build/sjcl');
|
|
||||||
|
|
||||||
describe('SJCL Jacobi', function() {
|
describe('SJCL Jacobi', function() {
|
||||||
it('(15/13) = -1', function () {
|
it('(15/13) = -1', function () {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
var sjcl = require('../build/sjcl');
|
|
||||||
|
|
||||||
function testExp(vec) {
|
function testExp(vec) {
|
||||||
var actual = new sjcl.bn(vec.g).powermodMontgomery(new sjcl.bn(vec.e),
|
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];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
637
test/transaction-manager-test.js
Normal file
637
test/transaction-manager-test.js
Normal file
@@ -0,0 +1,637 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var ws = require('ws');
|
||||||
|
var lodash = require('lodash');
|
||||||
|
var assert = require('assert-diff');
|
||||||
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
|
var Remote = require('ripple-lib').Remote;
|
||||||
|
var SerializedObject = require('ripple-lib').SerializedObject;
|
||||||
|
var Transaction = require('ripple-lib').Transaction;
|
||||||
|
var TransactionManager = require('../src/js/ripple/transactionmanager')
|
||||||
|
.TransactionManager;
|
||||||
|
|
||||||
|
var LEDGER = require('./fixtures/transactionmanager').LEDGER;
|
||||||
|
var ACCOUNT = require('./fixtures/transactionmanager').ACCOUNT;
|
||||||
|
var ACCOUNT2 = require('./fixtures/transactionmanager').ACCOUNT2;
|
||||||
|
var SUBSCRIBE_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.SUBSCRIBE_RESPONSE;
|
||||||
|
var ACCOUNT_INFO_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.ACCOUNT_INFO_RESPONSE;
|
||||||
|
var TX_STREAM_TRANSACTION = require('./fixtures/transactionmanager')
|
||||||
|
.TX_STREAM_TRANSACTION;
|
||||||
|
var ACCOUNT_TX_TRANSACTION = require('./fixtures/transactionmanager')
|
||||||
|
.ACCOUNT_TX_TRANSACTION;
|
||||||
|
var ACCOUNT_TX_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.ACCOUNT_TX_RESPONSE;
|
||||||
|
var ACCOUNT_TX_ERROR = require('./fixtures/transactionmanager')
|
||||||
|
.ACCOUNT_TX_ERROR;
|
||||||
|
var SUBMIT_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.SUBMIT_RESPONSE;
|
||||||
|
var SUBMIT_TEC_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.SUBMIT_TEC_RESPONSE;
|
||||||
|
var SUBMIT_TER_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.SUBMIT_TER_RESPONSE;
|
||||||
|
var SUBMIT_TEF_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.SUBMIT_TEF_RESPONSE;
|
||||||
|
var SUBMIT_TEL_RESPONSE = require('./fixtures/transactionmanager')
|
||||||
|
.SUBMIT_TEL_RESPONSE;
|
||||||
|
|
||||||
|
describe('TransactionManager', function() {
|
||||||
|
var rippled;
|
||||||
|
var rippledConnection;
|
||||||
|
var remote;
|
||||||
|
var account;
|
||||||
|
var transactionManager;
|
||||||
|
|
||||||
|
before(function() {
|
||||||
|
sjcl.random.addEntropy(
|
||||||
|
'3045022100A58B0460BC5092CB4F96155C19125A4E079C870663F1D5E8BBC9BD', 256);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(function(done) {
|
||||||
|
rippled = new ws.Server({port: 5763});
|
||||||
|
|
||||||
|
rippled.on('connection', function(c) {
|
||||||
|
var ledger = lodash.extend({}, LEDGER);
|
||||||
|
c.sendJSON = function(v) {
|
||||||
|
try {
|
||||||
|
c.send(JSON.stringify(v));
|
||||||
|
} catch (e) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
c.sendResponse = function(baseResponse, ext) {
|
||||||
|
assert.strictEqual(typeof baseResponse, 'object');
|
||||||
|
assert.strictEqual(baseResponse.type, 'response');
|
||||||
|
c.sendJSON(lodash.extend(baseResponse, ext));
|
||||||
|
};
|
||||||
|
c.closeLedger = function() {
|
||||||
|
c.sendJSON(lodash.extend(ledger, {
|
||||||
|
ledger_index: ++ledger.ledger_index
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
c.on('message', function(m) {
|
||||||
|
m = JSON.parse(m);
|
||||||
|
rippled.emit('request_' + m.command, m, c);
|
||||||
|
});
|
||||||
|
rippledConnection = c;
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.on('request_subscribe', function(message, c) {
|
||||||
|
if (lodash.isEqual(message.streams, ['ledger', 'server'])) {
|
||||||
|
c.sendResponse(SUBSCRIBE_RESPONSE, {id: message.id});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rippled.on('request_account_info', function(message, c) {
|
||||||
|
if (message.account === ACCOUNT.address) {
|
||||||
|
c.sendResponse(ACCOUNT_INFO_RESPONSE, {id: message.id});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
remote = new Remote({servers: ['ws://localhost:5763']});
|
||||||
|
remote.setSecret(ACCOUNT.address, ACCOUNT.secret);
|
||||||
|
account = remote.account(ACCOUNT.address);
|
||||||
|
transactionManager = account._transactionManager;
|
||||||
|
|
||||||
|
remote.connect(function() {
|
||||||
|
setTimeout(done, 10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function(done) {
|
||||||
|
remote.disconnect(function() {
|
||||||
|
rippled.close();
|
||||||
|
setImmediate(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Normalize transaction', function() {
|
||||||
|
var t1 = TransactionManager.normalizeTransaction(TX_STREAM_TRANSACTION);
|
||||||
|
var t2 = TransactionManager.normalizeTransaction(ACCOUNT_TX_TRANSACTION);
|
||||||
|
|
||||||
|
[t1, t2].forEach(function(t) {
|
||||||
|
assert(t.hasOwnProperty('metadata'));
|
||||||
|
assert(t.hasOwnProperty('tx_json'));
|
||||||
|
assert.strictEqual(t.validated, true);
|
||||||
|
assert.strictEqual(t.ledger_index, 1);
|
||||||
|
assert.strictEqual(t.engine_result, 'tesSUCCESS');
|
||||||
|
assert.strictEqual(t.type, 'transaction');
|
||||||
|
assert.strictEqual(t.tx_json.hash,
|
||||||
|
'01D66ACBD00B2A8F5D66FC8F67AC879CAECF49BC94FB97CF24F66B8406F4C040');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Handle received transaction', function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
|
||||||
|
transaction.once('success', function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
rippledConnection.sendJSON(TX_STREAM_TRANSACTION);
|
||||||
|
});
|
||||||
|
it('Handle received transaction -- failed', function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
|
||||||
|
transaction.once('error', function(err) {
|
||||||
|
assert.strictEqual(err.engine_result, 'tecINSUFF_FEE_P');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
rippledConnection.sendJSON(lodash.extend({ }, TX_STREAM_TRANSACTION, {
|
||||||
|
engine_result: 'tecINSUFF_FEE_P'
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
it('Handle received transaction -- not submitted', function(done) {
|
||||||
|
rippledConnection.sendJSON(TX_STREAM_TRANSACTION);
|
||||||
|
|
||||||
|
remote.once('transaction', function() {
|
||||||
|
assert(transactionManager.getPending().getReceived(
|
||||||
|
TX_STREAM_TRANSACTION.transaction.hash));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Handle received transaction -- Account mismatch', function(done) {
|
||||||
|
var tx = lodash.extend({ }, TX_STREAM_TRANSACTION);
|
||||||
|
lodash.extend(tx.transaction, {
|
||||||
|
Account: 'rMP2Y5EZrVZdFKsow11NoKTE5FjXuBQd3d'
|
||||||
|
});
|
||||||
|
rippledConnection.sendJSON(tx);
|
||||||
|
|
||||||
|
setImmediate(function() {
|
||||||
|
assert(!transactionManager.getPending().getReceived(
|
||||||
|
TX_STREAM_TRANSACTION.transaction.hash));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Handle received transaction -- not validated', function(done) {
|
||||||
|
var tx = lodash.extend({ }, TX_STREAM_TRANSACTION, {
|
||||||
|
validated: false
|
||||||
|
});
|
||||||
|
rippledConnection.sendJSON(tx);
|
||||||
|
|
||||||
|
setImmediate(function() {
|
||||||
|
assert(!transactionManager.getPending().getReceived(
|
||||||
|
TX_STREAM_TRANSACTION.transaction.hash));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Handle received transaction -- from account_tx', function(done) {
|
||||||
|
var transaction = Transaction.from_json(ACCOUNT_TX_TRANSACTION.tx);
|
||||||
|
transaction.once('success', function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.addId(ACCOUNT_TX_TRANSACTION.tx.hash);
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
transactionManager._transactionReceived(ACCOUNT_TX_TRANSACTION);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Adjust pending transaction fee', function(done) {
|
||||||
|
var transaction = new Transaction(remote);
|
||||||
|
transaction.tx_json = ACCOUNT_TX_TRANSACTION.tx;
|
||||||
|
|
||||||
|
transaction.once('fee_adjusted', function(a, b) {
|
||||||
|
assert.strictEqual(a, '10');
|
||||||
|
assert.strictEqual(b, '24');
|
||||||
|
assert.strictEqual(transaction.tx_json.Fee, '24');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
rippledConnection.sendJSON({
|
||||||
|
type: 'serverStatus',
|
||||||
|
load_base: 256,
|
||||||
|
load_factor: 256 * 2,
|
||||||
|
server_status: 'full'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Adjust pending transaction fee -- max fee exceeded', function(done) {
|
||||||
|
transactionManager._maxFee = 10;
|
||||||
|
|
||||||
|
var transaction = new Transaction(remote);
|
||||||
|
transaction.tx_json = ACCOUNT_TX_TRANSACTION.tx;
|
||||||
|
|
||||||
|
transaction.once('fee_adjusted', function() {
|
||||||
|
assert(false, 'Fee should not be adjusted');
|
||||||
|
});
|
||||||
|
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
rippledConnection.sendJSON({
|
||||||
|
type: 'serverStatus',
|
||||||
|
load_base: 256,
|
||||||
|
load_factor: 256 * 2,
|
||||||
|
server_status: 'full'
|
||||||
|
});
|
||||||
|
|
||||||
|
setImmediate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Adjust pending transaction fee -- no local fee', function(done) {
|
||||||
|
remote.local_fee = false;
|
||||||
|
|
||||||
|
var transaction = new Transaction(remote);
|
||||||
|
transaction.tx_json = ACCOUNT_TX_TRANSACTION.tx;
|
||||||
|
|
||||||
|
transaction.once('fee_adjusted', function() {
|
||||||
|
assert(false, 'Fee should not be adjusted');
|
||||||
|
});
|
||||||
|
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
rippledConnection.sendJSON({
|
||||||
|
type: 'serverStatus',
|
||||||
|
load_base: 256,
|
||||||
|
load_factor: 256 * 2,
|
||||||
|
server_status: 'full'
|
||||||
|
});
|
||||||
|
|
||||||
|
setImmediate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Wait ledgers', function(done) {
|
||||||
|
transactionManager._waitLedgers(3, done);
|
||||||
|
|
||||||
|
for (var i = 1; i <= 3; i++) {
|
||||||
|
rippledConnection.closeLedger();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Wait ledgers -- no ledgers', function(done) {
|
||||||
|
transactionManager._waitLedgers(0, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Update pending status', function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
transaction.submitIndex = 1;
|
||||||
|
transaction.tx_json.LastLedgerSequence = 10;
|
||||||
|
|
||||||
|
var receivedMissing = false;
|
||||||
|
var receivedLost = false;
|
||||||
|
|
||||||
|
transaction.once('missing', function() {
|
||||||
|
receivedMissing = true;
|
||||||
|
});
|
||||||
|
transaction.once('lost', function() {
|
||||||
|
receivedLost = true;
|
||||||
|
});
|
||||||
|
transaction.once('error', function(err) {
|
||||||
|
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||||
|
assert(receivedMissing);
|
||||||
|
assert(receivedLost);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
for (var i = 1; i <= 10; i++) {
|
||||||
|
rippledConnection.closeLedger();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Update pending status -- finalized before max ledger exceeded',
|
||||||
|
function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
transaction.submitIndex = 1;
|
||||||
|
transaction.tx_json.LastLedgerSequence = 10;
|
||||||
|
transaction.finalized = true;
|
||||||
|
|
||||||
|
var receivedMissing = false;
|
||||||
|
var receivedLost = false;
|
||||||
|
|
||||||
|
transaction.once('missing', function() {
|
||||||
|
receivedMissing = true;
|
||||||
|
});
|
||||||
|
transaction.once('lost', function() {
|
||||||
|
receivedLost = true;
|
||||||
|
});
|
||||||
|
transaction.once('error', function() {
|
||||||
|
assert(false, 'Should not err');
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.addId(TX_STREAM_TRANSACTION.transaction.hash);
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
for (var i = 1; i <= 10; i++) {
|
||||||
|
rippledConnection.closeLedger();
|
||||||
|
}
|
||||||
|
|
||||||
|
setImmediate(function() {
|
||||||
|
assert(!receivedMissing);
|
||||||
|
assert(!receivedLost);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Handle reconnect', function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
|
||||||
|
var binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
||||||
|
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
||||||
|
tx_blob: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.tx).to_hex(),
|
||||||
|
meta: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.meta).to_hex()
|
||||||
|
});
|
||||||
|
|
||||||
|
var hash = new SerializedObject(binaryTx.tx_blob).hash(0x54584E00).to_hex();
|
||||||
|
|
||||||
|
transaction.addId(hash);
|
||||||
|
|
||||||
|
transaction.once('success', function(res) {
|
||||||
|
assert.strictEqual(res.engine_result, 'tesSUCCESS');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
rippled.once('request_account_tx', function(m, req) {
|
||||||
|
var response = lodash.extend({}, ACCOUNT_TX_RESPONSE);
|
||||||
|
response.result.transactions = [binaryTx];
|
||||||
|
req.sendResponse(response, {id: m.id});
|
||||||
|
});
|
||||||
|
|
||||||
|
remote.disconnect(remote.connect);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Handle reconnect -- no matching transaction found', function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
|
||||||
|
var binaryTx = lodash.extend({}, ACCOUNT_TX_TRANSACTION, {
|
||||||
|
ledger_index: ACCOUNT_TX_TRANSACTION.tx.ledger_index,
|
||||||
|
tx_blob: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.tx).to_hex(),
|
||||||
|
meta: SerializedObject.from_json(ACCOUNT_TX_TRANSACTION.meta).to_hex()
|
||||||
|
});
|
||||||
|
|
||||||
|
transactionManager._request = function() {
|
||||||
|
// Resubmitting
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
rippled.once('request_account_tx', function(m, req) {
|
||||||
|
var response = lodash.extend({}, ACCOUNT_TX_RESPONSE);
|
||||||
|
response.result.transactions = [binaryTx];
|
||||||
|
req.sendResponse(response, {id: m.id});
|
||||||
|
});
|
||||||
|
|
||||||
|
remote.disconnect(remote.connect);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Handle reconnect -- account_tx error', function(done) {
|
||||||
|
var transaction = Transaction.from_json(TX_STREAM_TRANSACTION.transaction);
|
||||||
|
transactionManager.getPending().push(transaction);
|
||||||
|
|
||||||
|
transactionManager._resubmit = function() {
|
||||||
|
assert(false, 'Should not resubmit');
|
||||||
|
};
|
||||||
|
|
||||||
|
rippled.once('request_account_tx', function(m, req) {
|
||||||
|
req.sendResponse(ACCOUNT_TX_ERROR, {id: m.id});
|
||||||
|
setImmediate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
remote.disconnect(remote.connect);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Submit transaction', function(done) {
|
||||||
|
var transaction = remote.createTransaction('AccountSet', {
|
||||||
|
account: ACCOUNT.address
|
||||||
|
});
|
||||||
|
|
||||||
|
var receivedInitialSuccess = false;
|
||||||
|
var receivedProposed = false;
|
||||||
|
transaction.once('proposed', function(m) {
|
||||||
|
assert.strictEqual(m.engine_result, 'tesSUCCESS');
|
||||||
|
receivedProposed = true;
|
||||||
|
});
|
||||||
|
transaction.once('submitted', function(m) {
|
||||||
|
assert.strictEqual(m.engine_result, 'tesSUCCESS');
|
||||||
|
receivedInitialSuccess = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.once('request_submit', function(m, req) {
|
||||||
|
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||||
|
transaction.tx_json).to_hex());
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
req.sendResponse(SUBMIT_RESPONSE, {id: m.id});
|
||||||
|
setImmediate(function() {
|
||||||
|
var txEvent = lodash.extend({}, TX_STREAM_TRANSACTION);
|
||||||
|
txEvent.transaction = transaction.tx_json;
|
||||||
|
txEvent.transaction.hash = transaction.hash();
|
||||||
|
rippledConnection.sendJSON(txEvent);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.submit(function(err, res) {
|
||||||
|
assert(!err, 'Transaction submission should succeed');
|
||||||
|
assert(receivedInitialSuccess);
|
||||||
|
assert(receivedProposed);
|
||||||
|
assert.strictEqual(res.engine_result, 'tesSUCCESS');
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Submit transaction -- tec error', function(done) {
|
||||||
|
var transaction = remote.createTransaction('AccountSet', {
|
||||||
|
account: ACCOUNT.address,
|
||||||
|
set_flag: 'asfDisableMaster'
|
||||||
|
});
|
||||||
|
|
||||||
|
var receivedSubmitted = false;
|
||||||
|
transaction.once('proposed', function() {
|
||||||
|
assert(false, 'Should not receive proposed event');
|
||||||
|
});
|
||||||
|
transaction.once('submitted', function(m) {
|
||||||
|
assert.strictEqual(m.engine_result, 'tecNO_REGULAR_KEY');
|
||||||
|
receivedSubmitted = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.once('request_submit', function(m, req) {
|
||||||
|
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||||
|
transaction.tx_json).to_hex());
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
req.sendResponse(SUBMIT_TEC_RESPONSE, {id: m.id});
|
||||||
|
setImmediate(function() {
|
||||||
|
var txEvent = lodash.extend({}, TX_STREAM_TRANSACTION,
|
||||||
|
SUBMIT_TEC_RESPONSE.result);
|
||||||
|
txEvent.transaction = transaction.tx_json;
|
||||||
|
txEvent.transaction.hash = transaction.hash();
|
||||||
|
rippledConnection.sendJSON(txEvent);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.submit(function(err) {
|
||||||
|
assert(err, 'Transaction submission should not succeed');
|
||||||
|
assert(receivedSubmitted);
|
||||||
|
assert.strictEqual(err.engine_result, 'tecNO_REGULAR_KEY');
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Submit transaction -- ter error', function(done) {
|
||||||
|
var transaction = remote.createTransaction('Payment', {
|
||||||
|
account: ACCOUNT.address,
|
||||||
|
destination: ACCOUNT2.address,
|
||||||
|
amount: '1'
|
||||||
|
});
|
||||||
|
transaction.tx_json.Sequence = ACCOUNT_INFO_RESPONSE.result
|
||||||
|
.account_data.Sequence + 1;
|
||||||
|
|
||||||
|
var receivedSubmitted = false;
|
||||||
|
transaction.once('proposed', function() {
|
||||||
|
assert(false, 'Should not receive proposed event');
|
||||||
|
});
|
||||||
|
transaction.once('submitted', function(m) {
|
||||||
|
assert.strictEqual(m.engine_result, 'terNO_ACCOUNT');
|
||||||
|
receivedSubmitted = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.on('request_submit', function(m, req) {
|
||||||
|
var deserialized = new SerializedObject(m.tx_blob).to_json();
|
||||||
|
|
||||||
|
switch (deserialized.TransactionType) {
|
||||||
|
case 'Payment':
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
assert.deepEqual(deserialized, transaction.tx_json);
|
||||||
|
req.sendResponse(SUBMIT_TER_RESPONSE, {id: m.id});
|
||||||
|
break;
|
||||||
|
case 'AccountSet':
|
||||||
|
assert.strictEqual(deserialized.Account, ACCOUNT.address);
|
||||||
|
assert.strictEqual(deserialized.Flags, 2147483648);
|
||||||
|
req.sendResponse(SUBMIT_RESPONSE, {id: m.id});
|
||||||
|
req.closeLedger();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rippled.once('request_submit', function(m, req) {
|
||||||
|
req.sendJSON(lodash.extend({}, LEDGER, {
|
||||||
|
ledger_index: transaction.tx_json.LastLedgerSequence + 1
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.submit(function(err) {
|
||||||
|
assert(err, 'Transaction submission should not succeed');
|
||||||
|
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||||
|
assert(receivedSubmitted);
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||||
|
transactionManager.once('sequence_filled', done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Submit transaction -- tef error', function(done) {
|
||||||
|
var transaction = remote.createTransaction('AccountSet', {
|
||||||
|
account: ACCOUNT.address
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.tx_json.Sequence = ACCOUNT_INFO_RESPONSE.result
|
||||||
|
.account_data.Sequence - 1;
|
||||||
|
|
||||||
|
var receivedSubmitted = false;
|
||||||
|
var receivedResubmitted = false;
|
||||||
|
transaction.once('proposed', function() {
|
||||||
|
assert(false, 'Should not receive proposed event');
|
||||||
|
});
|
||||||
|
transaction.once('submitted', function(m) {
|
||||||
|
assert.strictEqual(m.engine_result, 'tefPAST_SEQ');
|
||||||
|
receivedSubmitted = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.on('request_submit', function(m, req) {
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||||
|
transaction.tx_json).to_hex());
|
||||||
|
req.sendResponse(SUBMIT_TEF_RESPONSE, {id: m.id});
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.once('request_submit', function(m, req) {
|
||||||
|
transaction.once('resubmitted', function() {
|
||||||
|
receivedResubmitted = true;
|
||||||
|
req.sendJSON(lodash.extend({}, LEDGER, {
|
||||||
|
ledger_index: transaction.tx_json.LastLedgerSequence + 1
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
req.closeLedger();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.submit(function(err) {
|
||||||
|
assert(err, 'Transaction submission should not succeed');
|
||||||
|
assert(receivedSubmitted);
|
||||||
|
assert(receivedResubmitted);
|
||||||
|
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Submit transaction -- tel error', function(done) {
|
||||||
|
var transaction = remote.createTransaction('AccountSet', {
|
||||||
|
account: ACCOUNT.address
|
||||||
|
});
|
||||||
|
|
||||||
|
var receivedSubmitted = false;
|
||||||
|
var receivedResubmitted = false;
|
||||||
|
transaction.once('proposed', function() {
|
||||||
|
assert(false, 'Should not receive proposed event');
|
||||||
|
});
|
||||||
|
transaction.once('submitted', function(m) {
|
||||||
|
assert.strictEqual(m.engine_result, 'telINSUF_FEE_P');
|
||||||
|
receivedSubmitted = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.on('request_submit', function(m, req) {
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 1);
|
||||||
|
assert.strictEqual(m.tx_blob, SerializedObject.from_json(
|
||||||
|
transaction.tx_json).to_hex());
|
||||||
|
req.sendResponse(SUBMIT_TEL_RESPONSE, {id: m.id});
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.once('request_submit', function(m, req) {
|
||||||
|
transaction.once('resubmitted', function() {
|
||||||
|
receivedResubmitted = true;
|
||||||
|
req.sendJSON(lodash.extend({}, LEDGER, {
|
||||||
|
ledger_index: transaction.tx_json.LastLedgerSequence + 1
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
req.closeLedger();
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.submit(function(err) {
|
||||||
|
assert(err, 'Transaction submission should not succeed');
|
||||||
|
assert(receivedSubmitted);
|
||||||
|
assert(receivedResubmitted);
|
||||||
|
assert.strictEqual(err.engine_result, 'tejMaxLedger');
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Submit transaction -- invalid secret', function(done) {
|
||||||
|
remote.setSecret(ACCOUNT.address, ACCOUNT.secret + 'z');
|
||||||
|
|
||||||
|
var transaction = remote.createTransaction('AccountSet', {
|
||||||
|
account: ACCOUNT.address
|
||||||
|
});
|
||||||
|
|
||||||
|
rippled.once('request_submit', function() {
|
||||||
|
assert(false, 'Should not request submit');
|
||||||
|
});
|
||||||
|
|
||||||
|
transaction.submit(function(err) {
|
||||||
|
assert.strictEqual(err.engine_result, 'tejSecretInvalid');
|
||||||
|
assert.strictEqual(transactionManager.getPending().length(), 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var Transaction = require('ripple-lib').Transaction;
|
||||||
var Transaction = utils.load_module('transaction').Transaction;
|
var TransactionQueue = require('ripple-lib').TransactionQueue;
|
||||||
var TransactionQueue = utils.load_module('transactionqueue').TransactionQueue;
|
|
||||||
|
|
||||||
describe('Transaction queue', function() {
|
describe('Transaction queue', function() {
|
||||||
it('Push transaction', function() {
|
it('Push transaction', function() {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
var utils = require('./testutils');
|
/* eslint-disable max-len */
|
||||||
|
'use strict';
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var Amount = utils.load_module('amount').Amount;
|
var Transaction = require('ripple-lib').Transaction;
|
||||||
var Transaction = utils.load_module('transaction').Transaction;
|
var TransactionQueue = require('ripple-lib').TransactionQueue;
|
||||||
var TransactionQueue = utils.load_module('transactionqueue').TransactionQueue;
|
var Remote = require('ripple-lib').Remote;
|
||||||
var Remote = utils.load_module('remote').Remote;
|
var Server = require('ripple-lib').Server;
|
||||||
var Server = utils.load_module('server').Server;
|
var sjcl = require('ripple-lib').sjcl;
|
||||||
|
|
||||||
var transactionResult = {
|
var transactionResult = {
|
||||||
engine_result: 'tesSUCCESS',
|
engine_result: 'tesSUCCESS',
|
||||||
@@ -18,7 +19,8 @@ var transactionResult = {
|
|||||||
metadata: {
|
metadata: {
|
||||||
AffectedNodes: [ ],
|
AffectedNodes: [ ],
|
||||||
TransactionIndex: 0,
|
TransactionIndex: 0,
|
||||||
TransactionResult: 'tesSUCCESS' },
|
TransactionResult: 'tesSUCCESS'
|
||||||
|
},
|
||||||
tx_json: {
|
tx_json: {
|
||||||
Account: 'rHPotLj3CNKaP4bQANcecEuT8hai3VpxfB',
|
Account: 'rHPotLj3CNKaP4bQANcecEuT8hai3VpxfB',
|
||||||
Amount: '1000000',
|
Amount: '1000000',
|
||||||
@@ -36,6 +38,11 @@ var transactionResult = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe('Transaction', function() {
|
describe('Transaction', function() {
|
||||||
|
before(function() {
|
||||||
|
sjcl.random.addEntropy(
|
||||||
|
'3045022100A58B0460BC5092CB4F96155C19125A4E079C870663F1D5E8BBC9BD', 256);
|
||||||
|
});
|
||||||
|
|
||||||
it('Success listener', function(done) {
|
it('Success listener', function(done) {
|
||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
|
|
||||||
@@ -190,7 +197,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
assert.strictEqual(transaction._accountSecret('rpzT237Ctpaa58KieifoK8RyBmmRwEcfhK'), 'shY1njzHAXp8Qt3bpxYW6RpoZtMKP');
|
assert.strictEqual(transaction._accountSecret('rpzT237Ctpaa58KieifoK8RyBmmRwEcfhK'), 'shY1njzHAXp8Qt3bpxYW6RpoZtMKP');
|
||||||
assert.strictEqual(transaction._accountSecret('rpdxPs9CR93eLAc5DTvAgv4S9XJ1CzKj1a'), 'ssboTJezioTq8obyvDU9tVo95NGGQ');
|
assert.strictEqual(transaction._accountSecret('rpdxPs9CR93eLAc5DTvAgv4S9XJ1CzKj1a'), 'ssboTJezioTq8obyvDU9tVo95NGGQ');
|
||||||
assert.strictEqual(transaction._accountSecret('rExistNot'), void(0));
|
assert.strictEqual(transaction._accountSecret('rExistNot'), undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Get fee units', function() {
|
it('Get fee units', function() {
|
||||||
@@ -236,7 +243,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Compute fee, no remote', function() {
|
it('Compute fee, no remote', function() {
|
||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
assert.strictEqual(transaction._computeFee(10), void(0));
|
assert.strictEqual(transaction._computeFee(10), undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Compute fee - no connected server', function() {
|
it('Compute fee - no connected server', function() {
|
||||||
@@ -261,7 +268,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
var transaction = new Transaction(remote);
|
var transaction = new Transaction(remote);
|
||||||
|
|
||||||
assert.strictEqual(transaction._computeFee(), void(0));
|
assert.strictEqual(transaction._computeFee(), undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Compute fee - one connected server', function() {
|
it('Compute fee - one connected server', function() {
|
||||||
@@ -428,7 +435,7 @@ describe('Transaction', function() {
|
|||||||
remote.trusted = true;
|
remote.trusted = true;
|
||||||
remote.local_signing = true;
|
remote.local_signing = true;
|
||||||
|
|
||||||
transaction.SigningPubKey = void(0);
|
transaction.SigningPubKey = undefined;
|
||||||
transaction.tx_json.Account = 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ';
|
transaction.tx_json.Account = 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ';
|
||||||
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoijX';
|
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoijX';
|
||||||
|
|
||||||
@@ -474,7 +481,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.Account = 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ';
|
transaction.tx_json.Account = 'rMWwx3Ma16HnqSd4H6saPisihX9aKpXxHJ';
|
||||||
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoij';
|
transaction._secret = 'sh2pTicynUEG46jjR4EoexHcQEoij';
|
||||||
|
|
||||||
assert.strictEqual(transaction.tx_json.Fee, void(0));
|
assert.strictEqual(transaction.tx_json.Fee, undefined);
|
||||||
|
|
||||||
assert(transaction.complete());
|
assert(transaction.complete());
|
||||||
|
|
||||||
@@ -540,7 +547,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.Sequence = 1;
|
transaction.tx_json.Sequence = 1;
|
||||||
transaction.tx_json.TransactionType = 'AccountSet';
|
transaction.tx_json.TransactionType = 'AccountSet';
|
||||||
|
|
||||||
assert.strictEqual(transaction.signingHash(), 'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE')
|
assert.strictEqual(transaction.signingHash(), 'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -555,7 +562,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.Sequence = 1;
|
transaction.tx_json.Sequence = 1;
|
||||||
transaction.tx_json.TransactionType = 'AccountSet';
|
transaction.tx_json.TransactionType = 'AccountSet';
|
||||||
|
|
||||||
assert.strictEqual(transaction.hash(), '1A860FC46D1DD9200560C64002418A4E8BBDE939957AC82D7B14D80A1C0E2EB5')
|
assert.strictEqual(transaction.hash(), '1A860FC46D1DD9200560C64002418A4E8BBDE939957AC82D7B14D80A1C0E2EB5');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -570,7 +577,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.Sequence = 1;
|
transaction.tx_json.Sequence = 1;
|
||||||
transaction.tx_json.TransactionType = 'AccountSet';
|
transaction.tx_json.TransactionType = 'AccountSet';
|
||||||
|
|
||||||
assert.strictEqual(transaction.hash('HASH_TX_SIGN'), 'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE')
|
assert.strictEqual(transaction.hash('HASH_TX_SIGN'), 'D1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||||
assert.strictEqual(transaction.hash('HASH_TX_SIGN_TESTNET'), '9FE7D27FC5B9891076B66591F99A683E01E0912986A629235459A3BD1961F341');
|
assert.strictEqual(transaction.hash('HASH_TX_SIGN_TESTNET'), '9FE7D27FC5B9891076B66591F99A683E01E0912986A629235459A3BD1961F341');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
@@ -639,12 +646,89 @@ describe('Transaction', function() {
|
|||||||
TxnSignature: '304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E'
|
TxnSignature: '304602210096C2F385530587DE573936CA51CB86B801A28F777C944E268212BE7341440B7F022100EBF0508A9145A56CDA7FAF314DF3BBE51C6EE450BA7E74D88516891A3608644E'
|
||||||
};
|
};
|
||||||
|
|
||||||
var expected_hash = "87366146D381AD971B97DD41CFAC1AE4670B0E996AB574B0CE18CE6467811868";
|
var expected_hash = '87366146D381AD971B97DD41CFAC1AE4670B0E996AB574B0CE18CE6467811868';
|
||||||
var transaction = Transaction.from_json(input_json);
|
var transaction = Transaction.from_json(input_json);
|
||||||
|
|
||||||
assert.deepEqual(transaction.hash(), expected_hash);
|
assert.deepEqual(transaction.hash(), expected_hash);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Get hash - complex transaction including Memo', function() {
|
||||||
|
var input_json = {
|
||||||
|
Account: 'rfe8yiZUymRPx35BEwGjhfkaLmgNsTytxT',
|
||||||
|
Amount: '1',
|
||||||
|
Destination: 'r9kiSEUEw6iSCNksDVKf9k3AyxjW3r1qPf',
|
||||||
|
Fee: '10',
|
||||||
|
Flags: 2147483648,
|
||||||
|
Memos: [
|
||||||
|
{
|
||||||
|
Memo: {
|
||||||
|
MemoData: '61BAF845AF6D4FB1AC08A58D817261457034F1431FB9997B3460EB355DCA98D9382181A0E0125B4B0D6DAAF9A460D09C9EFDEFB2BE49E545036028A04DDFCFE8CBDD03DA844EEF9235B708574319A0F1186ADA054D2A4E970E73C67BE3232662726CD59C53CA2EF1DC0939C4793B1794932832D08B9B830AA917BB7CADA5B76C93DC5E0C928B93D8C336D6722E4757332A61DEB7E2A601E8D3766D5285A26A8DFAFFFDDED8BD49D471B9D885F3DF0CC031D522197BC248A5E2BEFAB12BC4A8D77BAB1555C8B38C26254C7BE8563D97EDD806EB7BE3872C750F28B41F693CB179849E6E2105B627F63D390FDDEFE863D3E7C28D6465AA158E7D96920E0EEF0BCB7993EC652C97F876F1666DBA9DA0A612FF9FE0A00AF03B2D5DADFC71984CBC93CA5EAE4C50BDDC839C1C6C3EEAAB44E8493BB7940C0C9ACA0BFEC2999DF5109A3EC40E62280E252712CC91476FB45E40EE314A26F3259027349E47FDD1C21A8DBDF58635943A13B7E2690B4CD153E2FA147A035E979BBDD814635BAB79683D7F62A7D7FF433F9DD35D0967F591D6D3776FC8ADF53E04EAB1DBC5863CBB85FC6F8E5C8B75037DEA9FEEB6A4D5FDF0AEE3F1BDD42EB1B976E98784A15C851E4F3B6234BAFFD11204CB2B76A3CBAA02E3B21051FAF012504DF33CAF9567A333DCE2BB5F454D4BA4B319DF43ECBC86DE214A712A4E214E874092DC84E05B',
|
||||||
|
MemoType: 'D723898B3DB828F061BCE8DA8F3068B31E527CBDB4D0D22F3D4F5F2C6A961A84EF1189E9CBE2741FEC5C7A46011316D6F9A7769C8E8157E5209FED2D3F950E2763BEF07254327B0EDE9C3CFEB248997EDF148BA36E9D1167C87D73FE9F047FF167DF37B0EF30ABF8E5FD0DCC7E7B964EA0E60E8B2C27E2C7C214BD8334CE830B66BBD724172F7ADCEF491B9B495A979819944DF8EB3A13E4F03B2A8D6FFF332E5C9980A540BEDF659DFDDA03EC78F4F0279F90C8BFD494C15708197C2BAE5CA661EC75FB6E6097E7C5435F374332B7A066FBBC14C629E8EE6042A64226B075B9309BF5FE227CEEEB9CEC7A6B79E724BFBA2BA706F28EC9F3702FB3AFB4C74F0411C7EFDE7927D1ED0670C4F426B8C40F09EB715713788902A4374D8CC7E5111BCA39A97D1F9BD3BD56E28E6167E4DC97A7DEF5428B809D03AE72CB5BA1D25DE3523BC182E3B8905666A972A949B20C30C4FBD1D0A2D9AD8E46EFDBE4E46F4E340FE39F4AD315F5D9EBF7ED9BDC6D577375B56E0CD9FAF0BFA02453F90290E0962D6362048F737BEE3E0E1C46ECE61CCAF4C317B4135B2C5B5D5C4EE728002B2116BB1AF21903AB3F2E4E1A4FE4C5D76507C71C50670281DAB334C37503FB851FC25EC85C757976450004EC642E217D7F4B2E4B6DD820B5E3968B79CB9D7706F28714003C63F4B89AD1B6208A56DF5AFF02E5327A8EAA532BD3ED1ED0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Sequence: 74519,
|
||||||
|
SigningPubKey: '02BA5A9F27C34830542D7AA460B82D68AB34B410470108EE2DFFD9D280B49DB161',
|
||||||
|
TransactionType: 'Payment',
|
||||||
|
TxnSignature: '3045022100EA99CD20B47AB1C7AEF348102B515DB2FA26F1C9E7DC8FCAE72A763CEC37F21102206190F16F509A088E6303ACB66E9A6C1B9886C20B23F55C3B0721F2B97DC0926E',
|
||||||
|
date: 455562850,
|
||||||
|
hash: '4907745B5254B1093E037BA3250B95CFAF35C11CC2CA5E538A68FCE39D16F402',
|
||||||
|
inLedger: 7085699,
|
||||||
|
ledger_index: 7085699,
|
||||||
|
meta: {
|
||||||
|
AffectedNodes: [
|
||||||
|
{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: 'r9kiSEUEw6iSCNksDVKf9k3AyxjW3r1qPf',
|
||||||
|
Balance: '40900380802',
|
||||||
|
Flags: 0,
|
||||||
|
OwnerCount: 6,
|
||||||
|
Sequence: 98
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
LedgerIndex: '0EB37649FDF753A78DACB689057E827296F47AB7D04A7CB273C971A207E17960',
|
||||||
|
PreviousFields: {
|
||||||
|
Balance: '40900380801'
|
||||||
|
},
|
||||||
|
PreviousTxnID: '42C003842B5188E860B087DD509880C82263B31DE3DD6B5E4AC89AF541CF486E',
|
||||||
|
PreviousTxnLgrSeq: 5088491
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ModifiedNode: {
|
||||||
|
FinalFields: {
|
||||||
|
Account: 'rfe8yiZUymRPx35BEwGjhfkaLmgNsTytxT',
|
||||||
|
Balance: '35339588',
|
||||||
|
Domain: '9888A596C489373CF5C40858A66C8922C54A2BE9521E39CFFD0EF7A9906DAF298CDA4ADA16111A020C8B940CBABC4D39406381E0DE791147FAD0A5729F3546BF47D515FCDC80A85A52701CF9120C64DD6D41D0CF3DF2B56AEF6DBB463BB69F153BEEAC31D5300B8A3AE558122E192D7211DC0E4F547AD96B2E2F30F46AF8B5D76A58A75D764BA6FDC8E748EEC7A29C2F2A71784B8141D1A9E66544FF7C07025827C3BBCD66FA121D5E50407A622C803B33FCFBA4B2A7454BF86C32628DE0259EC0014783871BD3ADAF2E9F4E0FA421A68AFE1EF3ADEDD9CB24E783D284666BA8ABC2428F77D5550BE76751AA500A90E648CF7524CFC8E8785CB1ACBFB5F0AA50',
|
||||||
|
EmailHash: 'A9527827303A62DA5DB83FE47ACC1B62',
|
||||||
|
Flags: 1048576,
|
||||||
|
OwnerCount: 0,
|
||||||
|
RegularKey: 'rDLNuE5hfxbRzuXaNn7iUQBftoKfYQQtFA',
|
||||||
|
Sequence: 74520,
|
||||||
|
WalletLocator: 'D091F672A5A6FCE5AD3CD35BDD7E6FA15D4205D22E5EB36CBFB961D6E355EF9A'
|
||||||
|
},
|
||||||
|
LedgerEntryType: 'AccountRoot',
|
||||||
|
LedgerIndex: 'A85F8FD83E579C50AF595482824E2AC8C747E4673E83537E8CACCE595AA0C590',
|
||||||
|
PreviousFields: {
|
||||||
|
Balance: '35339599',
|
||||||
|
Sequence: 74519
|
||||||
|
},
|
||||||
|
PreviousTxnID: '3CB97C94E76F3A26C083DCA702E91446EB51D4DE62B25D8B7BA10F24FDA2F4E2',
|
||||||
|
PreviousTxnLgrSeq: 7085699
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
TransactionIndex: 13,
|
||||||
|
TransactionResult: 'tesSUCCESS',
|
||||||
|
delivered_amount: '1'
|
||||||
|
},
|
||||||
|
validated: true
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.deepEqual(Transaction.from_json(input_json).hash(), input_json.hash);
|
||||||
|
});
|
||||||
|
|
||||||
it('Serialize transaction', function() {
|
it('Serialize transaction', function() {
|
||||||
var input_json = {
|
var input_json = {
|
||||||
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
Account: 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
|
||||||
@@ -746,7 +830,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
assert.deepEqual(transaction.findId({
|
assert.deepEqual(transaction.findId({
|
||||||
F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE: transaction
|
F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE: transaction
|
||||||
}), void(0));
|
}), undefined);
|
||||||
|
|
||||||
transaction.addId('F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
transaction.addId('F1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE');
|
||||||
|
|
||||||
@@ -756,7 +840,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
assert.strictEqual(transaction.findId({
|
assert.strictEqual(transaction.findId({
|
||||||
Z1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE: transaction
|
Z1C15200CF532175F1890B6440AD223D3676140522BC11D2784E56760AE3B4FE: transaction
|
||||||
}), void(0));
|
}), undefined);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -770,7 +854,7 @@ describe('Transaction', function() {
|
|||||||
it('Set DestinationTag', function() {
|
it('Set DestinationTag', function() {
|
||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
transaction.destinationTag('tag');
|
transaction.destinationTag('tag');
|
||||||
assert.strictEqual(transaction.tx_json.DestinationTag, void(0));
|
assert.strictEqual(transaction.tx_json.DestinationTag, undefined);
|
||||||
transaction.destinationTag(1);
|
transaction.destinationTag(1);
|
||||||
assert.strictEqual(transaction.tx_json.DestinationTag, 1);
|
assert.strictEqual(transaction.tx_json.DestinationTag, 1);
|
||||||
});
|
});
|
||||||
@@ -779,7 +863,7 @@ describe('Transaction', function() {
|
|||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
|
|
||||||
transaction.invoiceID(1);
|
transaction.invoiceID(1);
|
||||||
assert.strictEqual(transaction.tx_json.InvoiceID, void(0));
|
assert.strictEqual(transaction.tx_json.InvoiceID, undefined);
|
||||||
|
|
||||||
transaction.invoiceID('DEADBEEF');
|
transaction.invoiceID('DEADBEEF');
|
||||||
assert.strictEqual(transaction.tx_json.InvoiceID, 'DEADBEEF00000000000000000000000000000000000000000000000000000000');
|
assert.strictEqual(transaction.tx_json.InvoiceID, 'DEADBEEF00000000000000000000000000000000000000000000000000000000');
|
||||||
@@ -792,7 +876,7 @@ describe('Transaction', function() {
|
|||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
|
|
||||||
transaction.clientID(1);
|
transaction.clientID(1);
|
||||||
assert.strictEqual(transaction._clientID, void(0));
|
assert.strictEqual(transaction._clientID, undefined);
|
||||||
|
|
||||||
transaction.clientID('DEADBEEF');
|
transaction.clientID('DEADBEEF');
|
||||||
assert.strictEqual(transaction._clientID, 'DEADBEEF');
|
assert.strictEqual(transaction._clientID, 'DEADBEEF');
|
||||||
@@ -802,11 +886,11 @@ describe('Transaction', function() {
|
|||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
|
|
||||||
transaction.lastLedger('a');
|
transaction.lastLedger('a');
|
||||||
assert.strictEqual(transaction.tx_json.LastLedgerSequence, void(0));
|
assert.strictEqual(transaction.tx_json.LastLedgerSequence, undefined);
|
||||||
assert(!transaction._setLastLedger);
|
assert(!transaction._setLastLedger);
|
||||||
|
|
||||||
transaction.lastLedger(NaN);
|
transaction.lastLedger(NaN);
|
||||||
assert.strictEqual(transaction.tx_json.LastLedgerSequence, void(0));
|
assert.strictEqual(transaction.tx_json.LastLedgerSequence, undefined);
|
||||||
assert(!transaction._setLastLedger);
|
assert(!transaction._setLastLedger);
|
||||||
|
|
||||||
transaction.lastLedger(12);
|
transaction.lastLedger(12);
|
||||||
@@ -846,8 +930,6 @@ describe('Transaction', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Rewrite transaction path', function() {
|
it('Rewrite transaction path', function() {
|
||||||
var transaction = new Transaction();
|
|
||||||
|
|
||||||
var path = [
|
var path = [
|
||||||
{
|
{
|
||||||
account: 'rP51ycDJw5ZhgvdKiRjBYZKYjsyoCcHmnY',
|
account: 'rP51ycDJw5ZhgvdKiRjBYZKYjsyoCcHmnY',
|
||||||
@@ -889,7 +971,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Rewrite transaction path - invalid path', function() {
|
it('Rewrite transaction path - invalid path', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
assert.strictEqual(Transaction._rewritePath(1), void(0));
|
assert.strictEqual(Transaction._rewritePath(1), undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -898,7 +980,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
transaction.pathAdd(1);
|
transaction.pathAdd(1);
|
||||||
|
|
||||||
assert.strictEqual(transaction.tx_json.Paths, void(0));
|
assert.strictEqual(transaction.tx_json.Paths, undefined);
|
||||||
|
|
||||||
var path = [
|
var path = [
|
||||||
{
|
{
|
||||||
@@ -949,7 +1031,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
transaction.paths(1);
|
transaction.paths(1);
|
||||||
|
|
||||||
assert.strictEqual(transaction.tx_json.Paths, void(0));
|
assert.strictEqual(transaction.tx_json.Paths, undefined);
|
||||||
|
|
||||||
transaction.paths([
|
transaction.paths([
|
||||||
[{
|
[{
|
||||||
@@ -999,7 +1081,7 @@ describe('Transaction', function() {
|
|||||||
it('Set SourceTag', function() {
|
it('Set SourceTag', function() {
|
||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
transaction.sourceTag('tag');
|
transaction.sourceTag('tag');
|
||||||
assert.strictEqual(transaction.tx_json.SourceTag, void(0));
|
assert.strictEqual(transaction.tx_json.SourceTag, undefined);
|
||||||
transaction.sourceTag(1);
|
transaction.sourceTag(1);
|
||||||
assert.strictEqual(transaction.tx_json.SourceTag, 1);
|
assert.strictEqual(transaction.tx_json.SourceTag, 1);
|
||||||
});
|
});
|
||||||
@@ -1007,7 +1089,7 @@ describe('Transaction', function() {
|
|||||||
it('Set TransferRate', function() {
|
it('Set TransferRate', function() {
|
||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
transaction.transferRate(1);
|
transaction.transferRate(1);
|
||||||
assert.strictEqual(transaction.tx_json.TransferRate, void(0));
|
assert.strictEqual(transaction.tx_json.TransferRate, undefined);
|
||||||
transaction.transferRate(1.5 * 1e9);
|
transaction.transferRate(1.5 * 1e9);
|
||||||
assert.strictEqual(transaction.tx_json.TransferRate, 1.5 * 1e9);
|
assert.strictEqual(transaction.tx_json.TransferRate, 1.5 * 1e9);
|
||||||
});
|
});
|
||||||
@@ -1018,33 +1100,33 @@ describe('Transaction', function() {
|
|||||||
transaction.setFlags();
|
transaction.setFlags();
|
||||||
assert.strictEqual(transaction.tx_json.Flags, 0);
|
assert.strictEqual(transaction.tx_json.Flags, 0);
|
||||||
|
|
||||||
var transaction = new Transaction();
|
var transaction2 = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction2.tx_json.TransactionType = 'Payment';
|
||||||
transaction.setFlags(Transaction.flags.Payment.PartialPayment);
|
transaction2.setFlags(Transaction.flags.Payment.PartialPayment);
|
||||||
assert.strictEqual(transaction.tx_json.Flags, 131072);
|
assert.strictEqual(transaction2.tx_json.Flags, 131072);
|
||||||
|
|
||||||
var transaction = new Transaction();
|
var transaction3 = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction3.tx_json.TransactionType = 'Payment';
|
||||||
transaction.setFlags('NoRippleDirect');
|
transaction3.setFlags('NoRippleDirect');
|
||||||
assert.strictEqual(transaction.tx_json.Flags, 65536);
|
assert.strictEqual(transaction3.tx_json.Flags, 65536);
|
||||||
|
|
||||||
var transaction = new Transaction();
|
var transaction4 = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction4.tx_json.TransactionType = 'Payment';
|
||||||
transaction.setFlags('PartialPayment', 'NoRippleDirect');
|
transaction4.setFlags('PartialPayment', 'NoRippleDirect');
|
||||||
assert.strictEqual(transaction.tx_json.Flags, 196608);
|
assert.strictEqual(transaction4.tx_json.Flags, 196608);
|
||||||
|
|
||||||
var transaction = new Transaction();
|
var transaction5 = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction5.tx_json.TransactionType = 'Payment';
|
||||||
transaction.setFlags([ 'LimitQuality', 'PartialPayment' ]);
|
transaction5.setFlags(['LimitQuality', 'PartialPayment']);
|
||||||
assert.strictEqual(transaction.tx_json.Flags, 393216);
|
assert.strictEqual(transaction5.tx_json.Flags, 393216);
|
||||||
|
|
||||||
var transaction = new Transaction();
|
var transaction6 = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction6.tx_json.TransactionType = 'Payment';
|
||||||
transaction.once('error', function(err) {
|
transaction6.once('error', function(err) {
|
||||||
assert.strictEqual(err.result, 'tejInvalidFlag');
|
assert.strictEqual(err.result, 'tejInvalidFlag');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
transaction.setFlags('asdf');
|
transaction6.setFlags('asdf');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Add Memo', function() {
|
it('Add Memo', function() {
|
||||||
@@ -1052,7 +1134,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
var memoType = 'message';
|
var memoType = 'message';
|
||||||
var memoFormat = 'application/json';
|
var memoFormat = 'json';
|
||||||
var memoData = {
|
var memoData = {
|
||||||
string: 'value',
|
string: 'value',
|
||||||
bool: true,
|
bool: true,
|
||||||
@@ -1065,9 +1147,9 @@ describe('Transaction', function() {
|
|||||||
{
|
{
|
||||||
Memo:
|
Memo:
|
||||||
{
|
{
|
||||||
MemoType: memoType,
|
MemoType: '6D657373616765',
|
||||||
MemoFormat: memoFormat,
|
MemoFormat: '6A736F6E',
|
||||||
MemoData: memoData
|
MemoData: '7B22737472696E67223A2276616C7565222C22626F6F6C223A747275652C22696E7465676572223A317D'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -1088,9 +1170,10 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
var expected = [
|
var expected = [
|
||||||
{
|
{
|
||||||
Memo: {
|
Memo:
|
||||||
MemoType: memo.memoType,
|
{
|
||||||
MemoData: memo.memoData
|
MemoType: '74797065',
|
||||||
|
MemoData: '64617461'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -1102,33 +1185,43 @@ describe('Transaction', function() {
|
|||||||
var transaction = new Transaction();
|
var transaction = new Transaction();
|
||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
transaction.addMemo('testkey', void(0), 'testvalue');
|
transaction.addMemo('testkey', undefined, 'testvalue');
|
||||||
transaction.addMemo('testkey2', void(0), 'testvalue2');
|
transaction.addMemo('testkey2', undefined, 'testvalue2');
|
||||||
transaction.addMemo('testkey3', 'text/html');
|
transaction.addMemo('testkey3', 'text/html');
|
||||||
transaction.addMemo(void(0), void(0), 'testvalue4');
|
transaction.addMemo(undefined, undefined, 'testvalue4');
|
||||||
transaction.addMemo('testkey4', 'text/html', '<html>');
|
transaction.addMemo('testkey4', 'text/html', '<html>');
|
||||||
|
|
||||||
var expected = [
|
var expected = [
|
||||||
{ Memo: {
|
{
|
||||||
MemoType: 'testkey',
|
Memo: {
|
||||||
MemoData: 'testvalue'
|
MemoType: '746573746B6579',
|
||||||
}},
|
MemoData: '7465737476616C7565'
|
||||||
{ Memo: {
|
}
|
||||||
MemoType: 'testkey2',
|
},
|
||||||
MemoData: 'testvalue2'
|
{
|
||||||
}},
|
Memo: {
|
||||||
{ Memo: {
|
MemoType: '746573746B657932',
|
||||||
MemoType: 'testkey3',
|
MemoData: '7465737476616C756532'
|
||||||
MemoFormat: 'text/html'
|
}
|
||||||
}},
|
},
|
||||||
{ Memo: {
|
{
|
||||||
MemoData: 'testvalue4'
|
Memo: {
|
||||||
}},
|
MemoType: '746573746B657933',
|
||||||
{ Memo: {
|
MemoFormat: '746578742F68746D6C'
|
||||||
MemoType: 'testkey4',
|
}
|
||||||
MemoFormat: 'text/html',
|
},
|
||||||
MemoData: '<html>'
|
{
|
||||||
}}
|
Memo: {
|
||||||
|
MemoData: '7465737476616C756534'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Memo: {
|
||||||
|
MemoType: '746573746B657934',
|
||||||
|
MemoFormat: '746578742F68746D6C',
|
||||||
|
MemoData: '3C68746D6C3E'
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
assert.deepEqual(transaction.tx_json.Memos, expected);
|
assert.deepEqual(transaction.tx_json.Memos, expected);
|
||||||
@@ -1157,7 +1250,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
transaction.addMemo(void(0), 1);
|
transaction.addMemo(undefined, 1);
|
||||||
}, /^Error: MemoFormat must be a string$/);
|
}, /^Error: MemoFormat must be a string$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1166,7 +1259,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
transaction.addMemo(void(0), 'России');
|
transaction.addMemo(undefined, 'России');
|
||||||
}, /^Error: MemoFormat must be valid ASCII$/);
|
}, /^Error: MemoFormat must be valid ASCII$/);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1179,7 +1272,7 @@ describe('Transaction', function() {
|
|||||||
assert.deepEqual(transaction.tx_json.Memos, [
|
assert.deepEqual(transaction.tx_json.Memos, [
|
||||||
{
|
{
|
||||||
Memo: {
|
Memo: {
|
||||||
MemoData: 'some_string'
|
MemoData: '736F6D655F737472696E67'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -1190,6 +1283,7 @@ describe('Transaction', function() {
|
|||||||
transaction.tx_json.TransactionType = 'Payment';
|
transaction.tx_json.TransactionType = 'Payment';
|
||||||
|
|
||||||
var memo = {
|
var memo = {
|
||||||
|
memoFormat: 'json',
|
||||||
memoData: {
|
memoData: {
|
||||||
string: 'string',
|
string: 'string',
|
||||||
int: 1,
|
int: 1,
|
||||||
@@ -1209,20 +1303,22 @@ describe('Transaction', function() {
|
|||||||
assert.deepEqual(transaction.tx_json.Memos, [
|
assert.deepEqual(transaction.tx_json.Memos, [
|
||||||
{
|
{
|
||||||
Memo: {
|
Memo: {
|
||||||
MemoData: memo.memoData
|
MemoFormat: '6A736F6E',
|
||||||
|
MemoData: '7B22737472696E67223A22737472696E67222C22696E74223A312C226172726179223A5B7B22737472696E67223A22737472696E67227D5D2C226F626A656374223A7B22737472696E67223A22737472696E67227D7D'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Construct AccountSet transaction', function() {
|
it('Set AccountTxnID', function() {
|
||||||
var transaction = new Transaction().accountSet('rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm');
|
var transaction = new Transaction();
|
||||||
|
|
||||||
assert(transaction instanceof Transaction);
|
assert(transaction instanceof Transaction);
|
||||||
|
|
||||||
|
transaction.accountTxnID('75C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4F');
|
||||||
|
|
||||||
assert.deepEqual(transaction.tx_json, {
|
assert.deepEqual(transaction.tx_json, {
|
||||||
Flags: 0,
|
Flags: 0,
|
||||||
TransactionType: 'AccountSet',
|
AccountTxnID: '75C5A92212AA82A89C3824F6F071FE49C95C45DE9113EB51763A217DBACB5B4F'
|
||||||
Account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm'
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1239,6 +1335,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() {
|
it('Construct AccountSet transaction - params object', function() {
|
||||||
var transaction = new Transaction().accountSet({
|
var transaction = new Transaction().accountSet({
|
||||||
account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
account: 'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
||||||
@@ -1258,7 +1366,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Construct AccountSet transaction - invalid account', function() {
|
it('Construct AccountSet transaction - invalid account', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().accountSet('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm');
|
new Transaction().accountSet('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1291,7 +1399,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Construct OfferCancel transaction - invalid account', function() {
|
it('Construct OfferCancel transaction - invalid account', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().offerCancel('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 1);
|
new Transaction().offerCancel('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1493,7 +1601,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Construct Payment transaction - invalid account', function() {
|
it('Construct Payment transaction - invalid account', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().payment(
|
new Transaction().payment(
|
||||||
'xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
'xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
||||||
'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe',
|
'r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe',
|
||||||
'1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe'
|
'1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe'
|
||||||
@@ -1503,7 +1611,7 @@ describe('Transaction', function() {
|
|||||||
|
|
||||||
it('Construct Payment transaction - invalid destination', function() {
|
it('Construct Payment transaction - invalid destination', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction().payment(
|
new Transaction().payment(
|
||||||
'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
'rsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm',
|
||||||
'xr36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe',
|
'xr36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe',
|
||||||
'1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe'
|
'1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe'
|
||||||
@@ -1572,7 +1680,7 @@ describe('Transaction', function() {
|
|||||||
it('Construct TrustSet transaction - invalid account', function() {
|
it('Construct TrustSet transaction - invalid account', function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var limit = '1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe';
|
var limit = '1/USD/r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe';
|
||||||
var transaction = new Transaction().trustSet('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', limit, 1.0, 1.0);
|
new Transaction().trustSet('xrsLEU1TPdCJPPysqhWYw9jD97xtG5WqSJm', limit, 1.0, 1.0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1580,9 +1688,9 @@ describe('Transaction', function() {
|
|||||||
var remote = new Remote();
|
var remote = new Remote();
|
||||||
var transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
var transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
||||||
|
|
||||||
assert.strictEqual(transaction.callback, void(0));
|
assert.strictEqual(transaction.callback, undefined);
|
||||||
assert.strictEqual(transaction._errorHandler, void(0));
|
assert.strictEqual(transaction._errorHandler, undefined);
|
||||||
assert.strictEqual(transaction._successHandler, void(0));
|
assert.strictEqual(transaction._successHandler, undefined);
|
||||||
assert.strictEqual(transaction.listeners('error').length, 1);
|
assert.strictEqual(transaction.listeners('error').length, 1);
|
||||||
|
|
||||||
var account = remote.addAccount('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
var account = remote.addAccount('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWe');
|
||||||
@@ -1603,13 +1711,13 @@ describe('Transaction', function() {
|
|||||||
receivedSuccess = true;
|
receivedSuccess = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
function submitCallback(err, res) {
|
function submitCallback(err) {
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert(receivedSuccess);
|
assert(receivedSuccess);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
transaction.submit(submitCallback);
|
transaction.submit(submitCallback);
|
||||||
|
|
||||||
@@ -1642,14 +1750,14 @@ describe('Transaction', function() {
|
|||||||
receivedError = true;
|
receivedError = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
function submitCallback(err, res) {
|
function submitCallback(err) {
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
assert(err);
|
assert(err);
|
||||||
assert.strictEqual(err.constructor.name, 'RippleError');
|
assert.strictEqual(err.constructor.name, 'RippleError');
|
||||||
assert(receivedError);
|
assert(receivedError);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
transaction.submit(submitCallback);
|
transaction.submit(submitCallback);
|
||||||
});
|
});
|
||||||
@@ -1669,7 +1777,7 @@ describe('Transaction', function() {
|
|||||||
it('Submit transaction - invalid account', function(done) {
|
it('Submit transaction - invalid account', function(done) {
|
||||||
var remote = new Remote();
|
var remote = new Remote();
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
var transaction = new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWeZ');
|
new Transaction(remote).accountSet('r36xtKNKR43SeXnGn7kN4r4JdQzcrkqpWeZ');
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -1679,7 +1787,9 @@ describe('Transaction', function() {
|
|||||||
remote.setSecret('rJaT8TafQfYJqDm8aC5n3Yx5yWEL2Ery79', 'snPwFATthTkKnGjEW73q3TL4yci1Q');
|
remote.setSecret('rJaT8TafQfYJqDm8aC5n3Yx5yWEL2Ery79', 'snPwFATthTkKnGjEW73q3TL4yci1Q');
|
||||||
|
|
||||||
var server = new Server(remote, 'wss://s1.ripple.com:443');
|
var server = new Server(remote, 'wss://s1.ripple.com:443');
|
||||||
server._computeFee = function() { return '12'; };
|
server._computeFee = function() {
|
||||||
|
return '12';
|
||||||
|
};
|
||||||
server._connected = true;
|
server._connected = true;
|
||||||
|
|
||||||
remote._servers.push(server);
|
remote._servers.push(server);
|
||||||
@@ -1695,7 +1805,7 @@ describe('Transaction', function() {
|
|||||||
transaction.abort();
|
transaction.abort();
|
||||||
});
|
});
|
||||||
|
|
||||||
transaction.submit(function(err, res) {
|
transaction.submit(function(err) {
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
assert(err);
|
assert(err);
|
||||||
assert.strictEqual(err.result, 'tejAbort');
|
assert.strictEqual(err.result, 'tejAbort');
|
||||||
@@ -1737,5 +1847,3 @@ describe('Transaction', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//vim:sw=2:sts=2:ts=8:et
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils');
|
var UInt128 = require('ripple-lib').UInt128;
|
||||||
var UInt128 = utils.load_module('uint128').UInt128;
|
|
||||||
var config = require('./testutils').get_config();
|
|
||||||
|
|
||||||
describe('UInt', function() {
|
describe('UInt', function() {
|
||||||
describe('128', function() {
|
describe('128', function() {
|
||||||
@@ -11,8 +9,8 @@ describe('UInt', function() {
|
|||||||
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
|
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
|
||||||
});
|
});
|
||||||
it('should create 00000000000000000000000000000001 when called with 1', function () {
|
it('should create 00000000000000000000000000000001 when called with 1', function () {
|
||||||
var val = UInt128.from_number(0);
|
var val = UInt128.from_number(1);
|
||||||
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
|
assert.strictEqual(val.to_hex(), '00000000000000000000000000000001');
|
||||||
});
|
});
|
||||||
it('should create 000000000000000000000000FFFFFFFF when called with 0xFFFFFFFF', function () {
|
it('should create 000000000000000000000000FFFFFFFF when called with 0xFFFFFFFF', function () {
|
||||||
var val = UInt128.from_number(0xFFFFFFFF);
|
var val = UInt128.from_number(0xFFFFFFFF);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
var fs = require('fs');
|
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var utils = require('./testutils').load_module('utils');
|
var utils = require('ripple-lib').utils;
|
||||||
|
|
||||||
describe('Utils', function() {
|
describe('Utils', function() {
|
||||||
describe('hexToString and stringToHex', 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