Compare commits

...

136 Commits

Author SHA1 Message Date
Geert Weening
25cf6c52e4 Bump version to 0.12.1-rc5 2015-03-18 17:24:24 -07:00
Geert Weening
7859ef6145 Update release notes 2015-03-18 17:23:46 -07:00
Geert Weening
6efaa4ac7e Merge pull request #311 from vhpoet/patch-4
[FIX] Amount: clone in ratio_human, product_human
2015-03-18 17:21:21 -07:00
Vahe Hovhannisyan
19e17a8431 [FIX] Amount: clone in ratio_human, product_human
Amount.ratio_human and Amount.product_human should change and return the cloned Amount object.
2015-03-18 17:09:17 -07:00
Geert Weening
c865ae9734 Bump version to 0.12.1-rc4 2015-03-17 11:19:34 -07:00
Geert Weening
6959f74073 Update release notes 2015-03-17 11:14:36 -07:00
Chris Clark
9f4d21e976 Merge pull request #310 from darkdarkdragon/release-base-decode-fix
[FIX] fix Base:decode
2015-03-17 10:12:07 -07:00
Ivan Tivonenko
719f39c01c [FIX] fix Base:decode
check for invalid input in decoded data
2015-03-17 05:53:02 +02:00
Geert Weening
25bb9c7320 Bump version to 0.12.1-rc3 2015-03-11 11:49:30 -07:00
Geert Weening
a160e16abd Update release notes 2015-03-11 11:48:46 -07:00
Geert Weening
ec31841aa5 Merge pull request #305 from geertweening/add-default-rippling-flag
Add DefaultRipple account flag
2015-03-11 11:41:49 -07:00
wltsmrz
3e249902c4 Add DefaultRipple account flag 2015-03-10 11:44:50 -07:00
Geert Weening
21bb766f06 Update release notes 2015-03-10 11:30:34 -07:00
Geert Weening
a883151400 Bump version to 0.12.1-rc2 2015-03-09 10:06:04 -07:00
Geert Weening
3c7fe82cbd Regenerate shrinkwrap 2015-03-09 10:05:49 -07:00
Geert Weening
899fc09704 Update release notes 2015-03-09 10:03:32 -07:00
Geert Weening
daa45a44b9 Merge pull request #297 from ripple/add-log-info
Add filename and line number to log, use log.warn() for deprecations
2015-03-09 09:45:18 -07:00
Geert Weening
52494628c3 Merge pull request #301 from ripple/amount-strict-mode
Add Amount.strict_mode for toggling range validation
2015-03-06 19:54:58 -08:00
Geert Weening
dbf5d21b72 Merge pull request #303 from clark800/morebasetest
[TASK] Fix issues in base.js and add more tests
2015-03-06 19:53:27 -08:00
wltsmrz
441bd4dfbf Lint remote.js 2015-03-06 19:06:24 -08:00
wltsmrz
8452f05dda Lint log.js 2015-03-06 18:36:27 -08:00
Chris Clark
0d2325e646 [TASK] Fix seed-test.js lint errors 2015-03-06 17:41:42 -08:00
wltsmrz
90329d3d73 Add filename and line number to log, use log.warn() for deprecations 2015-03-06 17:35:24 -08:00
Chris Clark
ca83a142f8 [TASK] Fix issues in base.js and add more tests 2015-03-06 17:33:52 -08:00
wltsmrz
d3b2d3d5c5 Merge pull request #304 from clark800/fix/travis_eslint2
[FIX] Fix bug in .travis.yml generation of list of modified files in pul...
2015-03-06 17:18:55 -08:00
Chris Clark
255177487c [FIX] Fix bug in .travis.yml generation of list of modified files in pull request 2015-03-06 15:53:52 -08:00
wltsmrz
ed0b75bcde Use new Amount(NaN) rather than Amount.NaN() 2015-03-06 15:38:44 -08:00
Chris Clark
06500a7909 Merge pull request #302 from clark800/fix/travis_eslint
[FIX] Don't lint deleted files and pull eslintrc from javascript-style-g...
2015-03-06 13:32:47 -08:00
wltsmrz
6e16bf68ae Lint serializedobject test 2015-03-06 13:01:57 -08:00
Chris Clark
ad22480117 [FIX] Don't lint deleted files and pull eslintrc from javascript-style-guide repo to ensure that it is up to date 2015-03-06 11:20:20 -08:00
wltsmrz
2fcd09072f Lint serializedtypes.js 2015-03-06 01:10:22 -08:00
wltsmrz
f0c785b196 Lint amount.js 2015-03-06 01:06:58 -08:00
Geert Weening
84fe76bada Merge pull request #296 from ripple/fix-currency-parsing
Fix currency parsing of non-alphanumeric and no-currency currencies
2015-03-05 22:32:04 -08:00
wltsmrz
b5ed8f59a7 Add Amount.strict_mode for toggling range validation 2015-03-05 22:21:35 -08:00
Geert Weening
52526f90d7 Merge pull request #298 from clark800/basetest
[TEST] Add unit tests for Base
2015-03-05 13:08:56 -08:00
wltsmrz
99e6e81e65 Merge pull request #299 from boxbag/fix-taker-pays-funded
[FIX] fix taker pays funded calculation
2015-03-05 11:17:43 -08:00
Bo Chen
5af824f5cf [FIX] fix taker pays funded calculation
When calling `parseInt` on a string with scientific notation, it ignores the exponents.
2015-03-05 09:43:27 -08:00
wltsmrz
2166bb2e88 Fix currency parsing of non-alphanumeric and no-currency currencies 2015-03-04 19:10:39 -08:00
Chris Clark
ae884c0200 [TEST] Add unit tests for Base 2015-03-04 13:02:36 -08:00
wltsmrz
423ec7d08a Merge pull request #294 from clark800/baseconverter
Refactor base conversion
2015-03-03 20:23:08 -08:00
Chris Clark
914cd6ecb2 Add unit tests for convertBase 2015-03-03 12:22:42 -08:00
Geert Weening
f221c82859 Merge pull request #293 from boxbag/offer-quality
Offer quality
2015-03-03 10:52:38 -08:00
wltsmrz
d57be723e6 Merge pull request #295 from stevenzeiler/ripple-wallet-version
[TASK] Bump ripple-wallet-generator patch version
2015-03-02 16:58:40 -08:00
Steven Zeiler
777554809a [TASK] Bump ripple-wallet-generator patch version 2015-03-02 16:53:52 -08:00
Chris Clark
f2b63fa4a8 Refactor base conversion 2015-02-27 21:28:23 -08:00
Bo Chen
4d06ce7454 [FIX] fix eslint errors 2015-02-27 16:12:06 -08:00
Bo Chen
8da6ec5fa3 [TASK] reverse skip of order book tests 2015-02-27 09:18:01 -08:00
Bo Chen
2a5a8b498d [FIX] fix handling of quality in order book 2015-02-27 09:18:01 -08:00
Bo Chen
a9b7d7d793 Merge pull request #292 from ripple/revert-286-set-user-agent
Revert "Set User-Agent Header with ripple-lib/{version}"
2015-02-27 09:17:27 -08:00
Bo Chen
6578cf5dd7 Revert "Set User-Agent Header with ripple-lib/{version}" 2015-02-26 14:40:07 -08:00
Geert Weening
2e21e8a43c Merge pull request #290 from ripple/transactionmanager-tests
Add TransactionManager test
2015-02-26 12:48:42 -08:00
Geert Weening
176e1fd9d4 Merge pull request #291 from ripple/update-binary-format
Update binary format
2015-02-26 11:41:34 -08:00
wltsmrz
c3b274b18f Add TransactionManager test 2015-02-25 18:49:59 -08:00
wltsmrz
8e134918fb Update binary format 2015-02-25 18:39:42 -08:00
wltsmrz
2b531d2a1f Disable breaking OrderBook tests 2015-02-25 01:36:12 -08:00
Geert Weening
87317dd54a Merge pull request #289 from ripple/fix-setregularkey-transaction-format
Fix RegularKey requirement in SetRegularKey transaction format
2015-02-24 09:23:48 -08:00
wltsmrz
618548c88d Merge pull request #273 from clark800/feature/eslint
[TASK] Add eslint enforcement to travis.yml
2015-02-23 17:50:41 -08:00
Chris Clark
b62f42006c [TASK] Add eslint enforcement to travis.yml 2015-02-23 16:34:22 -08:00
wltsmrz
c275174f27 Fix RegularKey requirement in SetRegularKey transaction format 2015-02-23 13:09:50 -08:00
Geert Weening
af4ed295e0 Bump version to 0.12.1-rc1 2015-02-23 09:25:42 -08:00
Geert Weening
7614a03ea8 Update release notes 2015-02-23 09:24:13 -08:00
Geert Weening
d9527726b6 Merge pull request #285 from boxbag/orderbook-fix
[FIX] fix order funded amount calculation
2015-02-23 09:16:44 -08:00
Geert Weening
05f4099709 Merge pull request #288 from ripple/fix-setfee-transaction-format
Fix Features field requirement in SetFee transaction format
2015-02-23 09:16:13 -08:00
wltsmrz
a20a649013 Fix Features field requirement in SetFee transaction format 2015-02-20 15:01:05 -08:00
Geert Weening
0e3e64105c Merge pull request #287 from clark800/bignumber_update
[TASK] Update bignumber.js and use new feature to simplify our code
2015-02-20 14:50:59 -08:00
Bo Chen
b2cdb1a6ae [FIX] fix order funded amount calculation 2015-02-20 14:49:47 -08:00
Alan Cohen
812432db96 Merge pull request #286 from lumberj/set-user-agent
Set User-Agent Header with ripple-lib/{version}
2015-02-20 10:23:32 -08:00
Alan Cohen
5b2c4aef2d Set User-Agent Header with ripple-lib/{version}
- This would be helpful for us to analyze usage of ripple-lib for anyone
  using the public rippled
2015-02-20 09:06:02 -08:00
Chris Clark
b7ccf424f4 [TASK] Update bignumber.js and use new feature to simplify our code 2015-02-19 19:51:05 -08:00
Geert Weening
77d5db168b Merge pull request #283 from clark800/feature/amount_sanity
[TASK] Disable parsing native amounts in foating point format
2015-02-17 14:29:38 -08:00
Chris Clark
e80cd1ff55 [TASK] Disable parsing native amounts in foating point format 2015-02-17 14:03:23 -08:00
Geert Weening
4ff25a21f6 Merge pull request #282 from boxbag/orderbook
[TEST] test and refactor orderbooks
2015-02-17 13:35:55 -08:00
Bo Chen
f184a71360 [TEST] test and refactor orderbooks 2015-02-13 13:37:57 -08:00
wltsmrz
fc38a9853d Merge pull request #281 from shekenahglory/develop
fix handling of false parameters in requestLedger
2015-02-11 14:24:27 -08:00
Matthew Fettig
6023efed41 fix handling of false parameters in requestLedger 2015-02-11 14:11:24 -08:00
Geert Weening
2abac6ce5c Bump version to 0.12.0 2015-02-11 12:24:40 -08:00
Geert Weening
53c7705c36 Update release notes 2015-02-11 12:24:00 -08:00
Geert Weening
7059ab65d6 Bump version to 0.12.0-rc3 2015-02-10 16:46:58 -08:00
Geert Weening
e133988b36 Update release notes 2015-02-10 16:46:36 -08:00
Geert Weening
9af27e7964 Merge branch 'develop' into release 2015-02-10 16:44:01 -08:00
Geert Weening
a57b3835fb Merge pull request #279 from ripple/fix-set-funded-amount
Fix IOU value passed to Amount.from_json()
2015-02-10 15:01:18 -08:00
Geert Weening
451cbb809e Disable Travis email notifications 2015-02-09 13:57:48 -08:00
wltsmrz
fd1b64393d Fix IOU value passed to Amount.from_json() 2015-02-09 13:41:40 -08:00
Geert Weening
ed875a35b4 Bump version to 0.12.0-rc2 2015-02-07 11:52:04 -08:00
Geert Weening
e85b0c2122 Update release notes 2015-02-07 11:51:20 -08:00
Geert Weening
f5b192f55f Merge branch 'develop' into release 2015-02-07 11:49:42 -08:00
Geert Weening
ff86d5381d Merge pull request #277 from geertweening/fix/memo_serialization
[FIX] unsymmetric memo serializing
2015-02-07 10:28:08 -08:00
Geert Weening
b63ac4addb [TASK] bump version to 0.12.0-rc1 2015-02-06 15:10:03 -08:00
Geert Weening
3e1a66d617 [DOC] update release notes 2015-02-06 15:09:02 -08:00
Geert Weening
93ed5a8cae Merge pull request #278 from ripple/fix-tests
Fix server-test for updated WS
2015-02-05 14:30:06 -08:00
wltsmrz
2e6e8807be Fix server-test for updated WS 2015-02-05 13:51:25 -08:00
Geert Weening
1ed36fabdb [FIX] unsymmetric memo serializing
treat memos as unknown binary, with optionally parsing unsynthesized hint fields
2015-02-05 11:13:37 -08:00
Geert Weening
8dc40ee379 Merge pull request #276 from ripple/bump-dependencies
Bump dependencies versions
2015-02-05 11:13:16 -08:00
Geert Weening
db4c7c89e3 Merge pull request #275 from ripple/mocha-reporter
Use mocha tap reporter only for Travis CI
2015-02-05 11:12:21 -08:00
wltsmrz
f9bc7cc746 Bump dependencies versions 2015-02-05 00:54:07 -08:00
wltsmrz
8f87ed65f9 Use mocha tap reporter only for Travis CI 2015-02-04 23:32:14 -08:00
Geert Weening
39c37631f3 Merge pull request #269 from clark800/feature/amount_cleanup
Cleanup amount.js
2015-02-04 14:06:17 -08:00
Chris Clark
d0fb291c4e Cleanup amount.js 2015-02-04 13:57:57 -08:00
wltsmrz
793523cbe9 Merge pull request #274 from clark800/fix/parse_human
[FIX] Handle invalid input in parse_human
2015-02-04 12:59:05 -08:00
wltsmrz
6da4dd9ecc Remove Gulp lint task, update eslint.json 2015-02-04 02:50:32 -08:00
Geert Weening
79892af8f8 Merge pull request #272 from ripple/fix-taker-gets-funded
Fix taker_gets_funded exceeding offer.TakerGets
2015-02-03 18:35:25 -08:00
Chris Clark
b86790c854 Check for null in isNumber 2015-02-03 18:23:18 -08:00
Chris Clark
c8f18c8c85 [FIX] Handle invalid input in parse_human 2015-02-03 18:06:15 -08:00
wltsmrz
b19ecb4482 Fix taker_gets_funded exceeding offer.TakerGets 2015-02-03 14:50:33 -08:00
wltsmrz
ba9af55aca Merge pull request #268 from ripple/remote-updates
Remote updates
2015-02-02 16:19:45 -08:00
wltsmrz
35d76b3520 Add deprecation warnings to request constructors
* The first argument to request constructor functions should be an
object containing request properties
* Improve Remote test coverage
2015-01-30 21:08:45 -08:00
Geert Weening
a5a0326092 Merge branch 'release' into develop 2015-01-29 15:39:18 -08:00
Geert Weening
a05833f845 bump version to 0.11.0 2015-01-29 14:58:28 -08:00
Bo Chen
c5deb60510 [FIX] update transaction binary parsing to account for XRP delivered amounts 2015-01-29 14:27:11 -08:00
Geert Weening
ff2ff89e3e Merge pull request #271 from boxbag/parse-binary-transaction
[FIX] update transaction binary parsing to account for XRP delivered amounts
2015-01-29 10:52:12 -08:00
Bo Chen
35a346a674 [FIX] update transaction binary parsing to account for XRP delivered amounts 2015-01-29 10:06:10 -08:00
Geert Weening
1217a95c52 Merge pull request #267 from clark800/feature/bignumberjs
[TASK] Refactor to use bignumber.js
2015-01-27 11:43:09 -08:00
Chris Clark
d025b4a0c3 [TASK] Refactor to use bignumber.js 2015-01-27 10:23:33 -08:00
Geert Weening
2cab50f920 [TASK] bump version to 0.11.0-rc3 2015-01-26 14:42:51 -08:00
Geert Weening
b049278dde [DOC] update release notes 2015-01-26 14:42:34 -08:00
Geert Weening
93335e74cb Merge branch 'release' into develop 2015-01-26 14:34:18 -08:00
wltsmrz
2833a7b66e Cleanup, deprecations
* REMOVED Remote storage interface
* REMOVED Remote "ping" configuration
* REMOVED Old/deprecated Remote server configuration
	  (websocket_ip, websocket_port)
* REMOVED browser "online" reconnect listener
2015-01-26 14:00:54 -08:00
wltsmrz
0d05b960f7 Merge pull request #266 from clark800/feature/perftest
[TASK] Add performance test "npm run perf"
2015-01-26 13:31:31 -08:00
Chris Clark
9fd64a9209 [TASK] Add performance test "npm run perf" 2015-01-23 17:03:57 -08:00
wltsmrz
1637d26de3 Merge pull request #264 from lumberj/bug/ledger_select
[BUG] `Request.prototype.ledgerSelect` can accept ledger_index as String
2015-01-21 10:13:06 -08:00
Alan Cohen
525ff9b75e [BUG] Request.prototype.ledgerSelect can accept ledger_index as String 2015-01-21 08:54:40 -08:00
wltsmrz
42e7932f59 Merge pull request #263 from lumberj/feature/requestOffer
[FEATURE] Remote.prototype.requestOffer
2015-01-20 18:40:42 -08:00
Alan Cohen
98f40abfc3 [FEATURE] Remote.prototype.requestOffer
See: https://ripple.com/build/rippled-apis/#ledger-entry

Rippled request
```js
{
  "id": 1,
  "command": "ledger_entry",
  "type": "offer",
  "offer": {"account": "rEQWVz1qN4DWw5J17s3DgXQzUuVYDSpK6M", "seq":5 },
  "ledger_index": 10850610
}
```

Response
```js
{
  "id": 7,
  "status": "success",
  "type": "response",
  "result": {
    "index": "F9DCCD26C770952D216085BF97D7E225F6A8B578ABD066AA92D7D06144B535EE",
    "ledger_index": 10850610,
    "node": {
      "Account": "rEQWVz1qN4DWw5J17s3DgXQzUuVYDSpK6M",
      "BookDirectory": "CF8D13399C6ED20BA82740CFA78E928DC8D498255249BA6351038D7EA4C68000",
      "BookNode": "0000000000000000",
      "Flags": 131072,
      "LedgerEntryType": "Offer",
      "OwnerNode": "0000000000000000",
      "PreviousTxnID": "64FAB660F9F5D9E7183E977701930AD09F372129C56E1685B68A914D8A43CA41",
      "PreviousTxnLgrSeq": 10850602,
      "Sequence": 5,
      "TakerGets": "1000000",
      "TakerPays": {
        "currency": "USD",
        "issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
        "value": "100"
      },
      "index": "F9DCCD26C770952D216085BF97D7E225F6A8B578ABD066AA92D7D06144B535EE"
    },
    "validated": false
  }
}
```
2015-01-20 18:17:33 -08:00
Geert Weening
55cd13ed4e Merge pull request #261 from boxbag/binary-default
[TASK] set binary as default for commands that accept the flag
2015-01-20 15:56:29 -08:00
Bo Chen
7cb113fcbc [TASK] set binary as default for commands that accept the flag 2015-01-20 14:10:22 -08:00
wltsmrz
ddbb999194 Merge pull request #262 from darkdarkdragon/develop-pathfind-fix
[FIX] properly close path find request
2015-01-16 16:17:32 -08:00
Ivan Tivonenko
1db96829ed [FIX] properly close path find request
path create uses broadcast, so close must
use this too
2015-01-17 01:48:18 +02:00
wltsmrz
3498dea18c Merge pull request #260 from ripplerm/develop
double check 'tes' code before emitting 'success'
2015-01-16 09:46:30 -08:00
ripplerm
97a8c87490 double check 'tes' code before emitting 'success'
result of a received transaction could be in 'tes' or 'tec'.
2015-01-17 01:01:27 +08:00
Geert Weening
fa72e09840 [TASK] bump version to 0.11.0-rc2 2015-01-15 16:24:14 -08:00
Geert Weening
d8cad710a5 [TASK] fix superagent dependency 2015-01-15 16:24:14 -08:00
Geert Weening
f91dcc33d3 [TASK] bump version to 0.11.0-rc1 2015-01-15 16:24:14 -08:00
Geert Weening
e5f524ec56 [DOC] update release notes 2015-01-15 16:24:14 -08:00
Geert Weening
f9b13cbc7f [TASK] re-add package.json for crypt 2015-01-15 16:24:14 -08:00
Geert Weening
1f860ecba6 Merge pull request #259 from ripple/use-eslint
Use eslint, remove jshint
2015-01-15 16:11:26 -08:00
wltsmrz
69a13b71ea Use eslint, remove jshint 2015-01-15 16:05:38 -08:00
61 changed files with 11839 additions and 5891 deletions

5
.gitignore vendored
View File

@@ -56,3 +56,8 @@ dist/
# Ignore flow output directory
out/
# Ignore perf test cache
scripts/cache
eslintrc

View File

@@ -1,10 +1,15 @@
language: node_js
node_js:
- "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:
- npm run coveralls
notifications:
email: false
webhooks:
urls:
- https://webhooks.gitter.im/e/d1ec4245f90231619d30

View File

@@ -1,3 +1,4 @@
'use strict';
var gulp = require('gulp');
var gutil = require('gulp-util');
var watch = require('gulp-watch');
@@ -8,22 +9,14 @@ var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var webpack = require('webpack');
var jshint = require('gulp-jshint');
var map = require('map-stream');
var bump = require('gulp-bump');
var react = require('gulp-react');
var flow = require('gulp-flowtype');
var argv = require('yargs').argv;
//var header = require('gulp-header');
// var header = require('gulp-header');
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 = [
'src/js/sjcl/core/sjcl.js',
'src/js/sjcl/core/aes.js',
@@ -67,33 +60,33 @@ gulp.task('concat-sjcl', function() {
.pipe(gulp.dest('./build/'));
});
gulp.task('build', [ 'concat-sjcl' ], function(callback) {
gulp.task('build', ['concat-sjcl'], function(callback) {
webpack({
cache: true,
entry: './src/js/ripple/index.js',
output: {
library: 'ripple',
path: './build/',
filename: [ 'ripple-', '.js' ].join(pkg.version)
},
filename: ['ripple-', '.js'].join(pkg.version)
}
}, callback);
});
gulp.task('build-min', [ 'build' ], function(callback) {
return gulp.src([ './build/ripple-', '.js' ].join(pkg.version))
gulp.task('build-min', ['build'], function() {
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
.pipe(uglify())
.pipe(rename([ 'ripple-', '-min.js' ].join(pkg.version)))
.pipe(rename(['ripple-', '-min.js'].join(pkg.version)))
.pipe(gulp.dest('./build/'));
});
gulp.task('build-debug', [ 'concat-sjcl' ], function(callback) {
gulp.task('build-debug', ['concat-sjcl'], function(callback) {
webpack({
cache: true,
entry: './src/js/ripple/index.js',
output: {
library: 'ripple',
path: './build/',
filename: [ 'ripple-', '-debug.js' ].join(pkg.version)
filename: ['ripple-', '-debug.js'].join(pkg.version)
},
debug: true,
devtool: 'eval'
@@ -106,11 +99,12 @@ gulp.task('build-debug', [ 'concat-sjcl' ], function(callback) {
*/
function buildUseError(cons) {
return 'var {<CONS>:function(){throw new Error("Class is unavailable in this build: <CONS>")}}'
.replace(new RegExp('<CONS>', 'g'), cons);
};
return ('var {<CONS>:function(){throw new Error('
+ '"Class is unavailable in this build: <CONS>")}}')
.replace(new RegExp('<CONS>', 'g'), cons);
}
gulp.task('build-core', [ 'concat-sjcl' ], function(callback) {
gulp.task('build-core', ['concat-sjcl'], function(callback) {
webpack({
entry: [
'./src/js/ripple/remote.js'
@@ -126,7 +120,7 @@ gulp.task('build-core', [ 'concat-sjcl' ], function(callback) {
output: {
library: 'ripple',
path: './build/',
filename: [ 'ripple-', '-core.js' ].join(pkg.version)
filename: ['ripple-', '-core.js'].join(pkg.version)
},
plugins: [
new webpack.optimize.UglifyJsPlugin()
@@ -134,99 +128,70 @@ gulp.task('build-core', [ 'concat-sjcl' ], function(callback) {
}, callback);
});
gulp.task('bower-build', [ 'build' ], function(callback) {
return gulp.src([ './build/ripple-', '.js' ].join(pkg.version))
gulp.task('bower-build', ['build'], function() {
return gulp.src(['./build/ripple-', '.js'].join(pkg.version))
.pipe(rename('ripple.js'))
.pipe(gulp.dest('./dist/'));
});
gulp.task('bower-build-min', [ 'build-min' ], function(callback) {
return gulp.src([ './build/ripple-', '-min.js' ].join(pkg.version))
gulp.task('bower-build-min', ['build-min'], function() {
return gulp.src(['./build/ripple-', '-min.js'].join(pkg.version))
.pipe(rename('ripple-min.js'))
.pipe(gulp.dest('./dist/'));
});
gulp.task('bower-build-debug', [ 'build-debug' ], function(callback) {
return gulp.src([ './build/ripple-', '-debug.js' ].join(pkg.version))
gulp.task('bower-build-debug', ['build-debug'], function() {
return gulp.src(['./build/ripple-', '-debug.js'].join(pkg.version))
.pipe(rename('ripple-debug.js'))
.pipe(gulp.dest('./dist/'));
});
gulp.task('bower-version', function() {
gulp.src('./dist/bower.json')
.pipe(bump({ version: pkg.version }))
.pipe(bump({version: pkg.version}))
.pipe(gulp.dest('./dist/'));
});
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('./jshintrc'))
.pipe(map(function(file, callback) {
if (file.jshint.success) {
return callback(null, file);
}
console.log('\n>' + file.path.substring(file.base.length) + '\n');
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 = ' ' + col1;
}
col1 += ' |';
console.log([ col1, col2, col3 ].join(' '));
}
});
callback(null, file);
}));
});
gulp.task('bower', ['bower-build', 'bower-build-min', 'bower-build-debug',
'bower-version']);
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
}));
.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'));
.pipe(watch('src/js/ripple/*.js'))
.pipe(cleanDest('out')) // delete outdated output file before stripping
.pipe(plumber()) // prevent an error in one file from ending build
.pipe(react({stripTypes: true}).on('error', logPluginError))
.pipe(filelog())
.pipe(gulp.dest('out'));
});
gulp.task('version-bump', function() {
if (!argv.type) {
throw new Error("No type found, pass it in using the --type argument");
throw new Error('No type found, pass it in using the --type argument');
}
gulp.src('./package.json')
.pipe(bump({ type: argv.type }))
.pipe(bump({type: argv.type}))
.pipe(gulp.dest('./'));
});
gulp.task('version-beta', function() {
gulp.src('./package.json')
.pipe(bump({ version: pkg.version + '-beta' }))
.pipe(bump({version: pkg.version + '-beta'}))
.pipe(gulp.dest('./'));
});
gulp.task('default', [ 'concat-sjcl', 'build', 'build-debug', 'build-min' ]);
gulp.task('default', ['concat-sjcl', 'build', 'build-debug', 'build-min']);

View File

@@ -1,3 +1,75 @@
##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)
+ [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)
+ [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)
@@ -8,8 +80,14 @@
+ [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)

View File

@@ -1,20 +0,0 @@
{
"browser": true,
"jquery": true,
"node": true,
"eqeqeq": true,
"eqnull": true,
"latedef": true,
"newcap": true,
"quotmark": "single",
"undef": true,
"unused": true,
"curly": true,
"freeze": true,
"nonbsp": true,
"maxparams": 4,
"maxdepth": 3,
"laxbreak": true
}

89
npm-shrinkwrap.json generated
View File

@@ -1,11 +1,16 @@
{
"name": "ripple-lib",
"version": "0.11.0-rc2",
"version": "0.12.1-rc5",
"dependencies": {
"async": {
"version": "0.8.0",
"from": "async@>=0.8.0 <0.9.0",
"resolved": "https://registry.npmjs.org/async/-/async-0.8.0.tgz"
"version": "0.9.0",
"from": "async@>=0.9.0 <0.10.0",
"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": {
"version": "1.2.1",
@@ -13,9 +18,9 @@
"resolved": "https://registry.npmjs.org/extend/-/extend-1.2.1.tgz"
},
"lodash": {
"version": "2.4.1",
"from": "lodash@>=2.4.1 <3.0.0",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz"
"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": {
"version": "2.5.0",
@@ -23,9 +28,9 @@
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz"
},
"ripple-wallet-generator": {
"version": "1.0.1",
"from": "ripple-wallet-generator@1.0.1",
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.1.tgz"
"version": "1.0.2",
"from": "ripple-wallet-generator@1.0.2",
"resolved": "https://registry.npmjs.org/ripple-wallet-generator/-/ripple-wallet-generator-1.0.2.tgz"
},
"superagent": {
"version": "0.18.2",
@@ -95,11 +100,6 @@
"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"
}
}
},
@@ -133,26 +133,51 @@
}
},
"ws": {
"version": "0.4.32",
"from": "ws@>=0.4.31 <0.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz",
"version": "0.7.1",
"from": "ws@>=0.7.1 <0.8.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-0.7.1.tgz",
"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": {
"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"
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.11.0-rc2",
"version": "0.12.1-rc5",
"description": "A JavaScript API for interacting with Ripple in Node.js and the browser",
"files": [
"src/js/*",
@@ -15,41 +15,45 @@
"test": "test"
},
"dependencies": {
"async": "~0.8.0",
"async": "~0.9.0",
"bignumber.js": "^2.0.3",
"extend": "~1.2.1",
"lodash": "^2.4.1",
"lodash": "^3.1.0",
"lru-cache": "~2.5.0",
"ripple-wallet-generator": "1.0.1",
"ws": "~0.4.31",
"ripple-wallet-generator": "1.0.2",
"ws": "~0.7.1",
"superagent": "^0.18.0"
},
"devDependencies": {
"assert-diff": "^1.0.1",
"coveralls": "~2.10.0",
"gulp": "~3.6.2",
"gulp-bump": "~0.1.10",
"eslint": "^0.13.0",
"gulp": "~3.8.10",
"gulp-bump": "~0.1.13",
"gulp-clean-dest": "^0.1.0",
"gulp-concat": "~2.2.0",
"gulp-concat": "~2.4.3",
"gulp-filelog": "^0.4.1",
"gulp-flowtype": "^0.4.1",
"gulp-jshint": "~1.5.5",
"gulp-plumber": "^0.6.6",
"gulp-react": "^2.0.0",
"gulp-rename": "~1.2.0",
"gulp-uglify": "~0.3.0",
"gulp-util": "^3.0.2",
"gulp-watch": "^3.0.0",
"istanbul": "~0.2.10",
"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": "~1.14.0",
"mocha": "~2.1.0",
"nock": "^0.34.1",
"webpack": "~1.1.11",
"webpack": "~1.5.3",
"yargs": "~1.3.1"
},
"scripts": {
"build": "node_modules/.bin/gulp",
"pretest": "node_modules/.bin/gulp concat-sjcl",
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter tap test/*-test.js",
"coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls"
"test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/_mocha -- --reporter ${MOCHA_REPORTER:=spec} test/*-test.js",
"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": {
"type": "git",

11
scripts/perf_test.sh Executable file
View 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"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,135 +1,125 @@
var sjcl = require('./utils').sjcl;
var utils = require('./utils');
var extend = require('extend');
var BigInteger = utils.jsbn.BigInteger;
'use strict';
var _ = require('lodash');
var sjcl = require('./utils').sjcl;
var utils = require('./utils');
var extend = require('extend');
var convertBase = require('./baseconverter');
var Base = {};
var alphabets = Base.alphabets = {
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
ripple: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
tipple: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
bitcoin: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
};
extend(Base, {
VER_NONE : 1,
VER_NODE_PUBLIC : 28,
VER_NODE_PRIVATE : 32,
VER_ACCOUNT_ID : 0,
VER_ACCOUNT_PUBLIC : 35,
VER_ACCOUNT_PRIVATE : 34,
VER_FAMILY_GENERATOR : 41,
VER_FAMILY_SEED : 33
VER_NONE: 1,
VER_NODE_PUBLIC: 28,
VER_NODE_PRIVATE: 32,
VER_ACCOUNT_ID: 0,
VER_ACCOUNT_PUBLIC: 35,
VER_ACCOUNT_PRIVATE: 34,
VER_FAMILY_GENERATOR: 41,
VER_FAMILY_SEED: 33
});
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) {
return sha256(sha256(bytes));
};
function encodeString(alphabet, input) {
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.
// <-- string at least as long as input.
Base.encode = function(input, alpha) {
var alphabet = alphabets[alpha || 'ripple'];
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('');
return this.encoders[alpha || 'ripple'].encode(input);
};
// --> input: String
// <-- array of bytes or undefined.
Base.decode = function(input, alpha) {
if (typeof input !== 'string') {
return void(0);
return undefined;
}
var alphabet = alphabets[alpha || 'ripple'];
var bi_base = new BigInteger(String(alphabet.length));
var bi_value = new BigInteger();
var i;
for (i = 0; i !== input.length && input[i] === alphabet[0]; i += 1) {
try {
return this.encoders[alpha || 'ripple'].decode(input);
} catch (e) {
return undefined;
}
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) {
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 result = true;
for (var i=0; i<4; i++) {
if (computed[i] !== checksum[i]) {
result = false;
break;
}
}
return result;
return _.isEqual(computed, checksum);
};
// --> input: Array
// <-- String
Base.encode_check = function(version, input, alphabet) {
var buffer = [].concat(version, input);
var check = sha256(sha256(buffer)).slice(0, 4);
var check = sha256(sha256(buffer)).slice(0, 4);
return Base.encode([].concat(buffer, check), alphabet);
};
// --> input : String
// <-- NaN || BigInteger
// <-- NaN || sjcl.bn
Base.decode_check = function(version, input, alphabet) {
var buffer = Base.decode(input, alphabet);
@@ -143,16 +133,10 @@ Base.decode_check = function(version, input, alphabet) {
}
// Multiple allowed versions
if (Array.isArray(version)) {
var match = false;
for (var i=0, l=version.length; i<l; i++) {
match |= version[i] === buffer[0];
}
if (!match) {
return NaN;
}
if (Array.isArray(version) && _.every(version, function(v) {
return v !== buffer[0];
})) {
return NaN;
}
if (!Base.verify_checksum(buffer)) {
@@ -163,7 +147,8 @@ Base.decode_check = function(version, input, alphabet) {
// intrepret the value as a negative number
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;

View 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;

View File

@@ -1,13 +1,19 @@
'use strict';
/*eslint no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/
/**
* Data type map.
*
* Mapping of type ids to data types. The type id is specified by the high
*
* 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
'Int16', // 1
@@ -20,11 +26,11 @@ var TYPES_MAP = exports.types = [
'Account', // 8
// 9-13 reserved
void(0), // 9
void(0), // 10
void(0), // 11
void(0), // 12
void(0), // 13
undefined, // 9
undefined, // 10
undefined, // 11
undefined, // 12
undefined, // 13
'Object', // 14
'Array', // 15
@@ -151,7 +157,7 @@ var FIELDS_MAP = exports.fields = {
8: 'RegularKey'
},
14: { // Object
1: void(0), //end of Object
1: undefined, // end of Object
2: 'TransactionMetaData',
3: 'CreatedNode',
4: 'DeletedNode',
@@ -163,7 +169,7 @@ var FIELDS_MAP = exports.fields = {
10: 'Memo'
},
15: { // Array
1: void(0), //end of Array
1: undefined, // end of Array
2: 'SigningAccounts',
3: 'TxnSignatures',
4: 'Signatures',
@@ -204,7 +210,6 @@ Object.keys(FIELDS_MAP).forEach(function(k1) {
});
});
var REQUIRED = exports.REQUIRED = 0,
OPTIONAL = exports.OPTIONAL = 1,
DEFAULT = exports.DEFAULT = 2;
@@ -229,7 +234,9 @@ exports.tx = {
[ 'WalletSize' , OPTIONAL ],
[ 'MessageKey' , OPTIONAL ],
[ 'Domain' , OPTIONAL ],
[ 'TransferRate' , OPTIONAL ]
[ 'TransferRate' , OPTIONAL ],
[ 'SetFlag' , OPTIONAL ],
[ 'ClearFlag' , OPTIONAL ]
]),
TrustSet: [20].concat(base, [
[ 'LimitAmount' , OPTIONAL ],
@@ -239,13 +246,14 @@ exports.tx = {
OfferCreate: [7].concat(base, [
[ 'TakerPays' , REQUIRED ],
[ 'TakerGets' , REQUIRED ],
[ 'Expiration' , OPTIONAL ]
[ 'Expiration' , OPTIONAL ],
[ 'OfferSequence' , OPTIONAL ]
]),
OfferCancel: [8].concat(base, [
[ 'OfferSequence' , REQUIRED ]
]),
SetRegularKey: [5].concat(base, [
[ 'RegularKey' , REQUIRED ]
[ 'RegularKey' , OPTIONAL ]
]),
Payment: [0].concat(base, [
[ 'Destination' , REQUIRED ],
@@ -271,12 +279,21 @@ exports.tx = {
EnableFeature: [100].concat(base, [
[ 'Feature' , REQUIRED ]
]),
EnableAmendment: [100].concat(base, [
[ 'Amendment' , REQUIRED ]
]),
SetFee: [101].concat(base, [
[ 'Features' , REQUIRED ],
[ 'BaseFee' , REQUIRED ],
[ 'ReferenceFeeUnits' , REQUIRED ],
[ 'ReserveBase' , 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_PERMISSION : 139,
tecNO_ENTRY : 140,
tecINSUFFICIENT_RESERVE : 141
tecINSUFFICIENT_RESERVE : 141,
tecNEED_MASTER_KEY : 142,
tecDST_TAG_NEEDED : 143,
tecINTERNAL : 144
};

View File

@@ -1,4 +1,6 @@
var extend = require('extend');
'use strict';
var extend = require('extend');
var UInt160 = require('./uint160').UInt160;
var utils = require('./utils');
var Float = require('./ieee754').Float;
@@ -16,8 +18,7 @@ var Currency = extend(function() {
// 3-letter code: ...
// XXX Should support hex, C++ doesn't currently allow it.
this._value = NaN;
this._value = NaN;
this._update();
}, UInt160);
@@ -32,25 +33,37 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
* Examples:
*
* USD => currency
* USD - Dollar => currency with optional full currency name
* XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate per year
* USD - Dollar => currency with optional full currency
* name
* XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate
* per year
* 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
* TYX - 30-Year Treasuries => Optional full currency with numbers and a dash
* TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers, dash and interest rate
* TYX - 30-Year Treasuries => Optional full currency with numbers
* 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
* ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
* (\s*-\s*[- \w]+) // optional full currency name following the dash 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)
* ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3
* digit numeric currency-code. See ISO 4217
* (\s*-\s*[- \w]+) // optional full currency name following the dash
* 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
*
*/
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) {
return (new Currency()).parse_json(j, shouldInterpretXrpAsIou);
@@ -58,39 +71,65 @@ Currency.from_json = function(j, shouldInterpretXrpAsIou) {
Currency.from_human = function(j, opts) {
return (new Currency().parse_human(j, opts));
}
};
// this._value = NaN on error.
Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
this._value = NaN;
switch (typeof j) {
case 'string':
if (j instanceof Currency) {
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') {
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;
}
// 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) {
var currencyCode = matches[1];
// for the currency 'XRP' case
// we drop everything else that could have been provided
// e.g. 'XRP - Ripple'
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
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 interest = matches[3] || '';
@@ -117,25 +156,28 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
currencyData[2] = currencyCode.charCodeAt(1) & 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
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
// Calculating the interest e-fold
// 0.5% demurrage is expressed 0.995, 0.005 less than 1
// 0.5% interest is expressed as 1.005, 0.005 more than 1
var interestEfold = secondsPerYear / Math.log(1 + percentage/100);
var interestEfold = secondsPerYear / Math.log(1 + percentage / 100);
var bytes = Float.toIEEE754Double(interestEfold);
for (var i=0; i<=bytes.length; i++) {
for (var i = 0; i <= bytes.length; i++) {
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 {
currencyData[12] = currencyCode.charCodeAt(0) & 0xff;
@@ -144,21 +186,6 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
}
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;
}
@@ -166,7 +193,6 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
return this;
};
Currency.prototype.parse_human = function(j) {
return this.parse_json(j);
};
@@ -176,6 +202,7 @@ Currency.prototype.parse_human = function(j) {
*
* You should never need to call this.
*/
Currency.prototype._update = function() {
var bytes = this.to_bytes();
@@ -183,7 +210,7 @@ Currency.prototype._update = function() {
var isZeroExceptInStandardPositions = true;
if (!bytes) {
return 'XRP';
return;
}
this._native = false;
@@ -192,8 +219,9 @@ Currency.prototype._update = function() {
this._interest_period = NaN;
this._iso_code = '';
for (var i=0; i<20; i++) {
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || bytes[i]===0);
for (var i = 0; i < 20; i++) {
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
&& (i === 12 || i === 13 || i === 14 || bytes[i] === 0);
}
if (isZeroExceptInStandardPositions) {
@@ -201,7 +229,7 @@ Currency.prototype._update = function() {
+ String.fromCharCode(bytes[13])
+ String.fromCharCode(bytes[14]);
if (this._iso_code === '\0\0\0') {
if (this._iso_code === '\u0000\u0000\u0000') {
this._native = true;
this._iso_code = 'XRP';
}
@@ -215,8 +243,8 @@ Currency.prototype._update = function() {
this._type = 1;
this._interest_start = (bytes[4] << 24) +
(bytes[5] << 16) +
(bytes[6] << 8) +
(bytes[7] );
(bytes[6] << 8) +
(bytes[7]);
this._interest_period = Float.fromIEEE754Double(bytes.slice(8, 16));
}
};
@@ -230,7 +258,8 @@ Currency.prototype.parse_bytes = function(byte_array) {
var isZeroExceptInStandardPositions = true;
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) {
@@ -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() {
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)
* used to calculate the interest over provided interval
* pass in one years worth of seconds to ge the yearly interest
* @returns {number} - interest for provided interval, can be negative for demurred currencies
* @param {number} referenceDate number of seconds since the Ripple Epoch
* (0:00 on January 1, 2000 UTC) used to calculate the
* interest over provided interval pass in one years
* 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()) {
return 0;
}
@@ -288,18 +322,20 @@ Currency.prototype.get_interest_at = function(referenceDate, decimals) {
}
// 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);
// convert to percentage
var interest = (interest*100)-100;
var decimalMultiplier = decimals ? Math.pow(10,decimals) : 100;
interest = (interest * 100) - 100;
var decimalMultiplier = decimals ? Math.pow(10, decimals) : 100;
// round to two decimals behind the dot
return Math.round(interest*decimalMultiplier) / decimalMultiplier;
return Math.round(interest * decimalMultiplier) / decimalMultiplier;
};
// XXX Currently we inherit UInt.prototype.is_valid, which is mostly fine.
@@ -307,9 +343,9 @@ Currency.prototype.get_interest_percentage_at = function(referenceDate, decimals
// We could be doing further checks into the internal format of the
// currency data, since there are some values that are invalid.
//
//Currency.prototype.is_valid = function() {
// return this._value instanceof BigInteger && ...;
//};
// Currency.prototype.is_valid = function() {
// return UInt.prototype.is_valid() && ...;
// };
Currency.prototype.to_json = function(opts) {
if (!this.is_valid()) {
@@ -317,28 +353,35 @@ Currency.prototype.to_json = function(opts) {
return 'XRP';
}
var opts = opts || {};
if (!opts) {
opts = {};
}
var currency;
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)) {
currency = this._iso_code + fullName;
if (opts.show_interest) {
var decimals = !isNaN(opts.decimals) ? opts.decimals : void(0);
var interestPercentage = this.has_interest() ? this.get_interest_percentage_at(this._interest_start + 3600 * 24 * 365, decimals) : 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;
currency += ' (' + interestPercentage + '%pa)';
}
} else {
// Fallback to returning the raw currency hex
currency = this.to_hex();
// XXX This is to maintain backwards compatibility, but it is very, very odd
// behavior, so we should deprecate it and get rid of it as soon as
// possible.
// XXX This is to maintain backwards compatibility, but it is very, very
// odd behavior, so we should deprecate it and get rid of it as soon as
// possible.
if (currency === Currency.HEX_ONE) {
currency = 1;
}
@@ -357,5 +400,3 @@ Currency.prototype.get_iso = function() {
};
exports.Currency = Currency;
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,25 +1,27 @@
exports.Remote = require('./remote').Remote;
exports.Request = require('./request').Request;
exports.Amount = require('./amount').Amount;
exports.Account = require('./account').Account;
exports.Transaction = require('./transaction').Transaction;
exports.Currency = require('./currency').Currency;
exports.Base = require('./base').Base;
exports.UInt128 = require('./uint128').UInt128;
exports.UInt160 = require('./uint160').UInt160;
exports.UInt256 = require('./uint256').UInt256;
exports.Seed = require('./seed').Seed;
exports.Meta = require('./meta').Meta;
'use strict';
exports.Remote = require('./remote').Remote;
exports.Request = require('./request').Request;
exports.Amount = require('./amount').Amount;
exports.Account = require('./account').Account;
exports.Transaction = require('./transaction').Transaction;
exports.Currency = require('./currency').Currency;
exports.Base = require('./base').Base;
exports.UInt128 = require('./uint128').UInt128;
exports.UInt160 = require('./uint160').UInt160;
exports.UInt256 = require('./uint256').UInt256;
exports.Seed = require('./seed').Seed;
exports.Meta = require('./meta').Meta;
exports.SerializedObject = require('./serializedobject').SerializedObject;
exports.RippleError = require('./rippleerror').RippleError;
exports.Message = require('./message').Message;
exports.binformat = require('./binformat');
exports.utils = require('./utils');
exports.Server = require('./server').Server;
exports.Wallet = require('./wallet');
exports.Ledger = require('./ledger').Ledger;
exports.RippleError = require('./rippleerror').RippleError;
exports.Message = require('./message').Message;
exports.binformat = require('./binformat');
exports.utils = require('./utils');
exports.Server = require('./server').Server;
exports.Wallet = require('./wallet');
exports.Ledger = require('./ledger').Ledger;
exports.TransactionQueue = require('./transactionqueue').TransactionQueue;
exports.RangeSet = require('./rangeset').RangeSet;
exports.RangeSet = require('./rangeset').RangeSet;
exports.convertBase = require('./baseconverter');
// Important: We do not guarantee any specific version of SJCL or for any
// specific features to be included. The version and configuration may change at
@@ -28,36 +30,35 @@ exports.RangeSet = require('./rangeset').RangeSet;
// However, for programs that are tied to a specific version of ripple.js like
// the official client, it makes sense to expose the SJCL instance so we don't
// have to include it twice.
exports.sjcl = require('./utils').sjcl;
exports.jsbn = require('./utils').jsbn;
exports.types = require('./serializedtypes');
exports.sjcl = require('./utils').sjcl;
exports.types = require('./serializedtypes');
exports.config = require('./config');
// camelCase to under_scored API conversion
function attachUnderscored(c) {
var o = exports[c];
function attachUnderscored(name) {
var o = exports[name];
Object.keys(o.prototype).forEach(function(key) {
var UPPERCASE = /([A-Z]{1})[a-z]+/g;
Object.keys(o.prototype).forEach(function(key) {
var UPPERCASE = /([A-Z]{1})[a-z]+/g;
if (!UPPERCASE.test(key)) {
return;
}
if (!UPPERCASE.test(key)) {
return;
}
var underscored = key.replace(UPPERCASE, function(c) {
return '_' + c.toLowerCase();
});
var underscored = key.replace(UPPERCASE, function(c) {
return '_' + c.toLowerCase();
});
o.prototype[underscored] = o.prototype[key];
});
};
o.prototype[underscored] = o.prototype[key];
});
}
[ 'Remote',
'Request',
'Transaction',
'Account',
'Server'
['Remote',
'Request',
'Transaction',
'Account',
'Server'
].forEach(attachUnderscored);
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,5 +1,10 @@
'use strict';
/**
* 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) {
if (!namespace) {
@@ -7,11 +12,11 @@ function Log(namespace) {
} else if (Array.isArray(namespace)) {
this._namespace = namespace;
} else {
this._namespace = [''+namespace];
this._namespace = [String(namespace)];
}
this._prefix = this._namespace.concat(['']).join(': ');
};
}
/**
* Create a sub-logger.
@@ -24,6 +29,9 @@ function Log(namespace) {
*
* log.info('connection successful');
* // prints: 'server: connection successful'
*
* @param {String} namespace logging prefix
* @return {Log} sub logger
*/
Log.prototype.sub = function(namespace) {
var subNamespace = this._namespace.slice();
@@ -43,17 +51,55 @@ Log.prototype._setParent = function(parentLogger) {
Log.makeLevel = function(level) {
return function() {
var args = Array.prototype.slice.call(arguments);
var args = Array.prototype.slice.apply(arguments);
args[0] = this._prefix + args[0];
Log.engine.logObject.apply(Log, args);
Log.engine.logObject.apply(Log, [level].concat(args[0], [args.slice(2)]));
};
};
Log.prototype.debug = Log.makeLevel(1);
Log.prototype.info = Log.makeLevel(2);
Log.prototype.warn = Log.makeLevel(3);
Log.prototype.info = Log.makeLevel(2);
Log.prototype.warn = Log.makeLevel(3);
Log.prototype.error = Log.makeLevel(4);
/**
* @param {String} message
* @param {Array} details
* @return {Array} prepared log info
*/
function getLogInfo(message, args) {
return [
// Timestamp
'[' + new Date().toISOString() + ']',
message,
'--',
// Location
(new Error()).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.
*
@@ -61,20 +107,33 @@ Log.prototype.error = Log.makeLevel(4);
* implementations. This is the logging engine used in Node.js.
*/
var BasicLogEngine = {
logObject: function logObject(msg) {
var args = Array.prototype.slice.call(arguments, 1);
logObject: function logObject(level, message, args) {
args = args.map(function(arg) {
return JSON.stringify(arg, null, 2);
});
args.unshift(msg);
args.unshift('[' + new Date().toISOString() + ']');
console.log.apply(console, args);
logMessage(level, getLogInfo(message, 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.
*
@@ -85,10 +144,12 @@ var NullLogEngine = {
logObject: function() {}
};
Log.engine = NullLogEngine;
if (console && console.log) {
if (typeof window !== 'undefined' && typeof console !== 'undefined') {
Log.engine = InteractiveLogEngine;
} else if (typeof console !== 'undefined' && console.log) {
Log.engine = BasicLogEngine;
} else {
Log.engine = NullLogEngine;
}
/**

View File

@@ -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;
}

View File

@@ -131,7 +131,6 @@ Meta.prototype.getNodes = function(options) {
}
};
Meta.prototype.getAffectedAccounts = function(from) {
if (this._affectedAccounts) {
return this._affectedAccounts;
@@ -164,7 +163,7 @@ Meta.prototype.getAffectedAccounts = function(from) {
this._affectedAccounts = utils.arrayUnique(accounts);
return this._affectedAccounts;
return this._affectedAccounts;
};
Meta.prototype.getAffectedBooks = function() {

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,7 @@ PathFind.prototype.create = 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('close');
};

File diff suppressed because it is too large Load Diff

View File

@@ -289,9 +289,7 @@ Request.prototype.setServer = function(server) {
break;
};
if (selected instanceof Server) {
this.server = selected;
}
this.server = selected;
return this;
};
@@ -355,8 +353,8 @@ Request.prototype.ledgerSelect = function(ledger) {
this.message.ledger_index = ledger;
break;
default:
if (typeof ledger === 'number' && isFinite(ledger)) {
this.message.ledger_index = ledger;
if (Number(ledger) && isFinite(Number(ledger))) {
this.message.ledger_index = Number(ledger);
} else if (/^[A-F0-9]{64}$/.test(ledger)) {
this.message.ledger_hash = ledger;
}

View File

@@ -6,8 +6,6 @@ var extend = require('extend');
var utils = require('./utils');
var sjcl = utils.sjcl;
var BigInteger = utils.jsbn.BigInteger;
var Base = require('./base').Base;
var UInt = require('./uint').UInt;
var UInt256 = require('./uint256').UInt256;
@@ -15,7 +13,6 @@ var UInt160 = require('./uint160').UInt160;
var KeyPair = require('./keypair').KeyPair;
var Seed = extend(function () {
// Internal form: NaN or BigInteger
this._curve = sjcl.ecc.curves.k256;
this._value = NaN;
}, UInt);
@@ -60,7 +57,7 @@ Seed.prototype.parse_passphrase = function (j) {
};
Seed.prototype.to_json = function () {
if (!(this._value instanceof BigInteger)) {
if (!(this.is_valid())) {
return NaN;
}

View File

@@ -1,13 +1,12 @@
var _ = require('lodash');
var assert = require('assert');
var extend = require('extend');
var binformat = require('./binformat');
var stypes = require('./serializedtypes');
var UInt256 = require('./uint256').UInt256;
var Crypt = require('./crypt').Crypt;
var utils = require('./utils');
var sjcl = utils.sjcl;
var BigInteger = utils.jsbn.BigInteger;
var TRANSACTION_TYPES = { };
@@ -27,6 +26,13 @@ Object.keys(binformat.ter).forEach(function(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) {
if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf)) ) {
this.buffer = buf;
@@ -38,11 +44,11 @@ function SerializedObject(buf) {
throw new Error('Invalid buffer passed.');
}
this.pointer = 0;
};
}
SerializedObject.from_json = function(obj) {
// 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 typedef;
@@ -103,8 +109,8 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
if (binformat.REQUIRED === requirement && obj[field] === void(0)) {
missing_fields.push(field);
};
};
}
}
if (missing_fields.length > 0) {
var object_name;
@@ -114,12 +120,12 @@ SerializedObject.check_no_missing_fields = function(typedef, obj) {
} else if (obj.LedgerEntryType != null){
object_name = SerializedObject.lookup_type_le(obj.LedgerEntryType);
} 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));
};
}
};
SerializedObject.prototype.append = function(bytes) {
@@ -152,7 +158,7 @@ function readOrPeek(advance) {
return result;
};
};
}
SerializedObject.prototype.read = readOrPeek(true);
@@ -209,8 +215,8 @@ SerializedObject.jsonify_structure = function(structure, field_name) {
if (typeof structure.to_json === 'function') {
output = structure.to_json();
} else if (structure instanceof BigInteger) {
output = structure.toString(16).toUpperCase();
} else if (structure instanceof sjcl.bn) {
output = ('0000000000000000' + normalize_sjcl_bn_hex(structure.toString()).toUpperCase()).slice(-16);
} else {
//new Array or Object
output = new structure.constructor();
@@ -250,7 +256,7 @@ SerializedObject.prototype.hash = function(prefix) {
var sign_buffer = new SerializedObject();
// Add hashing prefix
if ("undefined" !== typeof prefix) {
if ('undefined' !== typeof prefix) {
stypes.Int32.serialize(sign_buffer, prefix);
}
@@ -312,7 +318,7 @@ SerializedObject.sort_typedef = function(typedef) {
function sort_field_compare(a, b) {
// Sort by type id first, then by field id
return a[3] !== b[3] ? stypes[a[3]].id - stypes[b[3]].id : a[2] - b[2];
};
}
return typedef.sort(sort_field_compare);
};

View File

@@ -1,3 +1,5 @@
'use strict';
/**
* Type definitions for binary format.
*
@@ -6,74 +8,86 @@
* SerializedObject.parse() or SerializedObject.serialize().
*/
var assert = require('assert');
var extend = require('extend');
var assert = require('assert');
var extend = require('extend');
var GlobalBigNumber = require('bignumber.js');
var Amount = require('./amount').Amount;
var Currency = require('./currency').Currency;
var binformat = require('./binformat');
var utils = require('./utils');
var sjcl = utils.sjcl;
var utils = require('./utils');
var sjcl = utils.sjcl;
var SJCL_BN = sjcl.bn;
var UInt128 = require('./uint128').UInt128;
var UInt160 = require('./uint160').UInt160;
var UInt256 = require('./uint256').UInt256;
var Base = require('./base').Base;
var UInt128 = require('./uint128').UInt128;
var UInt160 = require('./uint160').UInt160;
var UInt256 = require('./uint256').UInt256;
var Base = require('./base').Base;
var amount = require('./amount');
var Amount = amount.Amount;
var Currency = amount.Currency;
var BigNumber = GlobalBigNumber.another({
ROUNDING_MODE: GlobalBigNumber.ROUND_HALF_UP,
DECIMAL_PLACES: 40
});
// Shortcuts
var hex = sjcl.codec.hex;
var bytes = sjcl.codec.bytes;
var utf8 = sjcl.codec.utf8String;
var BigInteger = utils.jsbn.BigInteger;
var SerializedType = function (methods) {
function SerializedType(methods) {
extend(this, methods);
};
}
function isNumber(val) {
return typeof val === 'number' && isFinite(val);
};
}
function isString(val) {
return typeof val === 'string';
};
}
function isHexInt64String(val) {
return isString(val) && /^[0-9A-F]{0,16}$/i.test(val);
};
}
function isCurrencyString(val) {
return isString(val) && /^[A-Z0-9]{3}$/.test(val);
};
function isBigInteger(val) {
return val instanceof BigInteger;
};
function serializeHex(so, hexData, noLength) {
var byteData = bytes.fromBits(hex.toBits(hexData));
function serializeBits(so, bits, noLength) {
var byteData = sjcl.codec.bytes.fromBits(bits);
if (!noLength) {
SerializedType.serialize_varint(so, byteData.length);
}
so.append(byteData);
};
}
function serializeHex(so, hexData, noLength) {
serializeBits(so, sjcl.codec.hex.toBits(hexData), noLength);
}
/**
* parses bytes as hex
*
* @param {Array} byte_array bytes
* @return {String} hex string
*/
function convertByteArrayToHex (byte_array) {
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase();
};
function convertStringToHex(string) {
return hex.fromBits(utf8.toBits(string)).toUpperCase();
function convertByteArrayToHex(byte_array) {
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array))
.toUpperCase();
}
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) {
@@ -88,7 +102,7 @@ SerializedType.serialize_varint = function (so, val) {
so.append([193 + (val >>> 8), val & 0xff]);
} else if (val <= 918744) {
val -= 12481;
so.append([ 241 + (val >>> 16), val >>> 8 & 0xff, val & 0xff ]);
so.append([241 + (val >>> 16), val >>> 8 & 0xff, val & 0xff]);
} else {
throw new Error('Variable integer overflow.');
}
@@ -116,13 +130,18 @@ SerializedType.prototype.parse_varint = function (so) {
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.
/**
* Convert an integer value into an array of bytes.
*
* The result is appended to the serialized object ('so').
*
* @param {Number} val value
* @param {Number} bytes byte size
* @return {Array} byte array
*/
function convertIntegerToByteArray(val, bytes) {
if (!isNumber(val)) {
@@ -130,19 +149,20 @@ function convertIntegerToByteArray(val, bytes) {
}
if (val < 0 || val >= Math.pow(256, bytes)) {
throw new Error('Value out of bounds');
throw new Error('Value out of bounds ');
}
var newBytes = [ ];
for (var i=0; i<bytes; i++) {
for (var i = 0; i < bytes; i++) {
newBytes.unshift(val >>> (i * 8) & 0xff);
}
return newBytes;
};
}
// Convert a certain number of bytes from the serialized object ('so') into an integer.
// Convert a certain number of bytes from the serialized object ('so') into an
// integer.
function readAndSum(so, bytes) {
var sum = 0;
@@ -150,14 +170,14 @@ function readAndSum(so, bytes) {
throw new Error('This function only supports up to four bytes.');
}
for (var i=0; i<bytes; i++) {
for (var i = 0; i < bytes; i++) {
var byte = so.read(1)[0];
sum += (byte << (8 * (bytes - i - 1)));
}
// Convert to unsigned integer
return sum >>> 0;
};
}
var STInt8 = exports.Int8 = new SerializedType({
serialize: function (so, val) {
@@ -170,6 +190,89 @@ var STInt8 = exports.Int8 = new SerializedType({
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({
serialize: function (so, val) {
so.append(convertIntegerToByteArray(val, 2));
@@ -201,40 +304,25 @@ var STInt64 = exports.Int64 = new SerializedType({
if (val < 0) {
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)) {
if (!isHexInt64String(val)) {
throw new Error('Not a valid hex Int64.');
}
bigNumObject = new BigInteger(val, 16);
} else if (isBigInteger(val)) {
if (val.compareTo(BigInteger.ZERO) < 0) {
bigNumObject = new SJCL_BN(val, 16);
} else if (val instanceof SJCL_BN) {
if (!val.greaterEquals(0)) {
throw new Error('Negative value for unsigned Int64 is invalid.');
}
bigNumObject = val;
} else {
throw new Error('Invalid type for Int64');
}
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
serializeBits(so, bigNumObject.toBits(64), true); // noLength = true
},
parse: function (so) {
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
// pessimistic numeric fraek. What doth lief?
var result = new BigInteger([0].concat(bytes), 256);
assert(result instanceof BigInteger);
return result;
return SJCL_BN.fromBits(sjcl.codec.bytes.toBits(bytes));
}
});
@@ -246,7 +334,7 @@ var STHash128 = exports.Hash128 = new SerializedType({
if (!hash.is_valid()) {
throw new Error('Invalid Hash128');
}
serializeHex(so, hash.to_hex(), true); //noLength = true
serializeBits(so, hash.to_bits(), true); // noLength = true
},
parse: function (so) {
return UInt128.from_bytes(so.read(16));
@@ -261,7 +349,7 @@ var STHash256 = exports.Hash256 = new SerializedType({
if (!hash.is_valid()) {
throw new Error('Invalid Hash256');
}
serializeHex(so, hash.to_hex(), true); //noLength = true
serializeBits(so, hash.to_bits(), true); // noLength = true
},
parse: function (so) {
return UInt256.from_bytes(so.read(32));
@@ -276,7 +364,7 @@ var STHash160 = exports.Hash160 = new SerializedType({
if (!hash.is_valid()) {
throw new Error('Invalid Hash160');
}
serializeHex(so, hash.to_hex(), true); //noLength = true
serializeBits(so, hash.to_bits(), true); // noLength = true
},
parse: function (so) {
return UInt160.from_bytes(so.read(20));
@@ -287,11 +375,12 @@ STHash160.id = 17;
// Internal
var STCurrency = new SerializedType({
serialize: function (so, val, xrp_as_ascii) {
serialize: function (so, val) {
var currencyData = val.to_bytes();
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);
@@ -301,10 +390,11 @@ var STCurrency = new SerializedType({
var currency = Currency.from_bytes(bytes);
// XXX Disabled check. Theoretically, the Currency class should support any
// UInt160 value and consider it valid. But it doesn't, so for the
// deserialization to be usable, we need to allow invalid results for now.
//if (!currency.is_valid()) {
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
//}
// deserialization to be usable, we need to allow invalid results for
// now.
// if (!currency.is_valid()) {
// throw new Error('Invalid currency: '+convertByteArrayToHex(bytes));
// }
return currency;
}
});
@@ -312,18 +402,26 @@ var STCurrency = new SerializedType({
var STAmount = exports.Amount = new SerializedType({
serialize: function (so, val) {
var amount = Amount.from_json(val);
if (!amount.is_valid()) {
throw new Error('Not a valid Amount object.');
}
var value = new BigNumber(amount.to_text());
var offset = value.e - 15;
// Amount (64-bit integer)
var valueBytes = utils.arraySet(8, 0);
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)
if (valueHex.length > 16) {
if (Amount.strict_mode && valueHex.length > 16) {
throw new Error('Value out of bounds');
}
@@ -331,7 +429,7 @@ var STAmount = exports.Amount = new SerializedType({
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
// Amount enforces the range correctly, but we'll clear them anyway just
// 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
hi |= ((97 + amount._offset) & 0xff) << 22;
hi |= ((97 + offset) & 0xff) << 22;
// Remaining 54 bits: mantissa
hi |= amount._value.shiftRight(32).intValue() & 0x3fffff;
lo = amount._value.intValue() & 0xffffffff;
var mantissaDecimal = utils.getMantissaDecimalString(value.abs());
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]);
@@ -374,16 +478,17 @@ var STAmount = exports.Amount = new SerializedType({
}
},
parse: function (so) {
var amount = new Amount();
var value_bytes = so.read(8);
var is_zero = !(value_bytes[0] & 0x7f);
for (var i=1; i<8; i++) {
for (var i = 1; i < 8; i++) {
is_zero = is_zero && !value_bytes[i];
}
var is_negative = !is_zero && !(value_bytes[0] & 0x40);
if (value_bytes[0] & 0x80) {
//non-native
// non-native
var currency = STCurrency.parse(so);
var issuer_bytes = so.read(20);
var issuer = UInt160.from_bytes(issuer_bytes);
@@ -391,26 +496,23 @@ var STAmount = exports.Amount = new SerializedType({
var offset = ((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
var mantissa_bytes = value_bytes.slice(1);
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 ) {
throw new Error('Invalid zero representation');
}
amount._value = value;
amount._offset = offset;
amount._currency = currency;
amount._issuer = issuer;
amount._is_native = false;
} else {
//native
var integer_bytes = value_bytes.slice();
integer_bytes[0] &= 0x3f;
amount._value = new BigInteger(integer_bytes, 256);
amount._is_native = true;
return Amount.from_json({
currency: currency,
issuer: issuer.to_json(),
value: valueString
});
}
amount._is_negative = !is_zero && !(value_bytes[0] & 0x40);
return amount;
// native
var integer_bytes = value_bytes.slice();
integer_bytes[0] &= 0x3f;
var integer_hex = utils.arrayToHex(integer_bytes);
var value = new BigNumber(integer_hex, 16);
return Amount.from_json((is_negative ? '-' : '') + value.toString());
}
});
@@ -418,7 +520,6 @@ STAmount.id = 6;
var STVL = exports.VariableLength = exports.VL = new SerializedType({
serialize: function (so, val) {
if (typeof val === 'string') {
serializeHex(so, val);
} else {
@@ -439,7 +540,7 @@ var STAccount = exports.Account = new SerializedType({
if (!account.is_valid()) {
throw new Error('Invalid account!');
}
serializeHex(so, account.to_hex());
serializeBits(so, account.to_bits());
},
parse: function (so) {
var len = this.parse_varint(so);
@@ -462,21 +563,21 @@ var STAccount = exports.Account = new SerializedType({
STAccount.id = 8;
var STPathSet = exports.PathSet = new SerializedType({
typeBoundary: 0xff,
typeEnd: 0x00,
typeAccount: 0x01,
typeCurrency: 0x10,
typeIssuer: 0x20,
typeBoundary: 0xff,
typeEnd: 0x00,
typeAccount: 0x01,
typeCurrency: 0x10,
typeIssuer: 0x20,
serialize: function (so, val) {
for (var i=0, l=val.length; i<l; i++) {
for (var i = 0, l = val.length; i < l; i++) {
// Boundary
if (i) {
STInt8.serialize(so, this.typeBoundary);
}
for (var j=0, l2=val[i].length; j<l2; j++) {
for (var j = 0, l2 = val[i].length; j < l2; j++) {
var entry = val[i][j];
//if (entry.hasOwnProperty('_value')) {entry = entry._value;}
// if (entry.hasOwnProperty('_value')) {entry = entry._value;}
var type = 0;
if (entry.account) {
@@ -492,7 +593,7 @@ var STPathSet = exports.PathSet = new SerializedType({
STInt8.serialize(so, type);
if (entry.account) {
so.append(UInt160.from_json(entry.account).to_bytes());
STHash160.serialize(so, entry.account);
}
if (entry.currency) {
@@ -501,7 +602,7 @@ var STPathSet = exports.PathSet = new SerializedType({
}
if (entry.issuer) {
so.append(UInt160.from_json(entry.issuer).to_bytes());
STHash160.serialize(so, entry.issuer);
}
}
}
@@ -518,61 +619,64 @@ 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 tag_byte;
/* eslint-disable no-cond-assign */
while ((tag_byte = so.read(1)[0]) !== this.typeEnd) {
//TODO: try/catch this loop, and catch when we run out of data without reaching the end of the data structure.
//Now determine: is this an end, boundary, or entry-begin-tag?
//console.log('Tag byte:', tag_byte);
// TODO: try/catch this loop, and catch when we run out of data without
// reaching the end of the data structure.
// Now determine: is this an end, boundary, or entry-begin-tag?
// console.log('Tag byte:', tag_byte);
if (tag_byte === this.typeBoundary) {
//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);
}
current_path = [ ]; //and start a new one.
current_path = [ ]; // and start a new one.
continue;
}
//It's an entry-begin tag.
//console.log('It's an entry-begin tag.');
// It's an entry-begin tag.
var entry = {};
var type = 0;
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.set_version(Base.VER_ACCOUNT_ID);
type = type | this.typeAccount;
}
if (tag_byte & this.typeCurrency) {
//console.log('entry.currency');
entry.currency = STCurrency.parse(so);
if (entry.currency.to_json() === 'XRP' && !entry.currency.is_native()) {
entry.non_native = true;
}
type = type | this.typeCurrency;
}
if (tag_byte & this.typeIssuer) {
//console.log('entry.issuer');
entry.issuer = STHash160.parse(so);
// Enable and set correct type of base-58 encoding
entry.issuer.set_version(Base.VER_ACCOUNT_ID);
//console.log('DONE WITH ISSUER!');
type = type | this.typeIssuer;
}
if (entry.account || entry.currency || entry.issuer) {
entry.type = type;
entry.type_hex = ('000000000000000' + type.toString(16)).slice(-16);
current_path.push(entry);
} else {
throw new Error('Invalid path entry'); //It must have at least something in it.
// It must have at least something in it.
throw new Error('Invalid path entry');
}
}
if (current_path) {
//close the current path, if there is one,
// close the current path, if there is one,
path_list.push(current_path);
}
@@ -583,9 +687,10 @@ var STPathSet = exports.PathSet = new SerializedType({
STPathSet.id = 18;
var STVector256 = exports.Vector256 = new SerializedType({
serialize: function (so, val) { //Assume val is an array of STHash256 objects.
var length_as_varint = SerializedType.serialize_varint(so, val.length * 32);
for (var i=0, l=val.length; i<l; i++) {
serialize: function(so, val) {
// 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++) {
STHash256.serialize(so, val[i]);
}
},
@@ -593,7 +698,7 @@ var STVector256 = exports.Vector256 = new SerializedType({
var length = this.parse_varint(so);
var output = [];
// length is number of bytes not number of Hash256
for (var i=0; i<length / 32; i++) {
for (var i = 0; i < length / 32; i++) {
output.push(STHash256.parse(so));
}
return output;
@@ -603,9 +708,8 @@ var STVector256 = exports.Vector256 = new SerializedType({
STVector256.id = 19;
// Internal
var STMemo = exports.STMemo = new SerializedType({
exports.STMemo = new SerializedType({
serialize: function(so, val, no_marker) {
var keys = [];
Object.keys(val).forEach(function (key) {
@@ -625,73 +729,64 @@ var STMemo = exports.STMemo = new SerializedType({
// Sort fields
keys = sort_fields(keys);
// store that we're dealing with json
var isJson = val.MemoFormat === 'json';
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);
}
keys.forEach(function(key) {
serialize(so, key, val[key]);
});
if (!no_marker) {
//Object ending marker
// Object ending marker
STInt8.serialize(so, 0xe1);
}
},
parse: function(so) {
var output = {};
while (so.peek(1)[0] !== 0xe1) {
var keyval = parse(so);
output[keyval[0]] = keyval[1];
}
if (output['MemoType'] !== void(0)) {
output['parsed_memo_type'] = convertHexToString(output['MemoType']);
}
if (output.MemoType !== undefined) {
try {
var parsedType = 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 {
output['parsed_memo_data'] = JSON.parse(convertHexToString(output['MemoData']));
} 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') {
output['parsed_memo_data'] = convertHexToString(output['MemoData']);
} 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_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({
serialize: function (so, val, no_marker) {
var keys = [];
@@ -814,12 +817,12 @@ var STObject = exports.Object = new SerializedType({
// Sort fields
keys = sort_fields(keys);
for (var i=0; i<keys.length; i++) {
for (var i = 0; i < keys.length; i++) {
serialize(so, keys[i], val[keys[i]]);
}
if (!no_marker) {
//Object ending marker
// Object ending marker
STInt8.serialize(so, 0xe1);
}
},
@@ -839,11 +842,12 @@ STObject.id = 14;
var STArray = exports.Array = new SerializedType({
serialize: function (so, val) {
for (var i=0, l=val.length; i<l; i++) {
for (var i = 0, l = val.length; i < l; i++) {
var keys = Object.keys(val[i]);
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];
@@ -851,7 +855,7 @@ var STArray = exports.Array = new SerializedType({
serialize(so, field_name, value);
}
//Array ending marker
// Array ending marker
STInt8.serialize(so, 0xf1);
},

View File

@@ -671,7 +671,7 @@ Server.prototype._handleResponseSubscribe = function(message) {
return;
}
if (!this._remote._allow_partial_history
if (!this._remote.allow_partial_history
&& !Server.hasFullLedgerHistory(message)) {
// Server has partial history and Remote has been configured to disallow
// servers with incomplete history

View File

@@ -134,7 +134,8 @@ Transaction.set_clear_flags = {
asfDisableMaster: 4,
asfAccountTxnID: 5,
asfNoFreeze: 6,
asfGlobalFreeze: 7
asfGlobalFreeze: 7,
asfDefaultRipple: 8
}
};
@@ -835,24 +836,40 @@ Transaction.prototype.addMemo = function(memoType, memoFormat, memoData) {
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 = {};
if (memoType) {
if (Transaction.MEMO_TYPES[memoType]) {
//XXX Maybe in the future we want a schema validator for
//memo types
memo.MemoType = Transaction.MEMO_TYPES[memoType];
} else {
memo.MemoType = memoType;
memoType = Transaction.MEMO_TYPES[memoType];
}
memo.MemoType = convertStringToHex(memoType);
}
if (memoFormat) {
memo.MemoFormat = memoFormat;
memo.MemoFormat = convertStringToHex(memoFormat);
}
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 });

View File

@@ -1,11 +1,13 @@
var util = require('util');
var assert = require('assert');
var async = require('async');
'use strict';
var util = require('util');
var assert = require('assert');
var async = require('async');
var EventEmitter = require('events').EventEmitter;
var Transaction = require('./transaction').Transaction;
var RippleError = require('./rippleerror').RippleError;
var Transaction = require('./transaction').Transaction;
var RippleError = require('./rippleerror').RippleError;
var PendingQueue = require('./transactionqueue').TransactionQueue;
var log = require('./log').internal.sub('transactionmanager');
var log = require('./log').internal.sub('transactionmanager');
/**
* @constructor TransactionManager
@@ -20,11 +22,11 @@ function TransactionManager(account) {
this._account = account;
this._accountID = account._account_id;
this._remote = account._remote;
this._nextSequence = void(0);
this._nextSequence = undefined;
this._maxFee = this._remote.max_fee;
this._maxAttempts = this._remote.max_attempts;
this._submissionTimeout = this._remote._submission_timeout;
this._lastLedgerOffset = this._remote._last_ledger_offset;
this._submissionTimeout = this._remote.submission_timeout;
this._lastLedgerOffset = this._remote.last_ledger_offset;
this._pending = new PendingQueue();
this._account.on('transaction-outbound', function(res) {
@@ -37,7 +39,7 @@ function TransactionManager(account) {
function updatePendingStatus(ledger) {
self._updatePendingStatus(ledger);
};
}
this._remote.on('ledger_closed', updatePendingStatus);
@@ -47,7 +49,7 @@ function TransactionManager(account) {
// hooking back into ledger_closed
self._remote.on('ledger_closed', updatePendingStatus);
});
};
}
this._remote.on('disconnect', function() {
self._remote.removeListener('ledger_closed', updatePendingStatus);
@@ -56,7 +58,7 @@ function TransactionManager(account) {
// Query server for next account transaction sequence
this._loadSequence();
};
}
util.inherits(TransactionManager, EventEmitter);
@@ -96,7 +98,7 @@ TransactionManager.normalizeTransaction = function(tx) {
var transaction = { };
var keys = Object.keys(tx);
for (var i=0; i<keys.length; i++) {
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
switch (k) {
case 'transaction':
@@ -162,7 +164,8 @@ TransactionManager.prototype._transactionReceived = function(tx) {
if (!(submission instanceof Transaction)) {
// 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
@@ -197,7 +200,7 @@ TransactionManager.prototype._adjustFees = function() {
transaction.once('presubmit', function() {
transaction.emit('error', 'tejMaxFeeExceeded');
});
};
}
this._pending.forEach(function(transaction) {
if (transaction._setFixedFee) {
@@ -209,7 +212,8 @@ TransactionManager.prototype._adjustFees = function() {
if (Number(newFee) > self._maxFee) {
// Max transaction fee exceeded, abort submission
return maxFeeExceeded(transaction);
maxFeeExceeded(transaction);
return;
}
transaction.tx_json.Fee = newFee;
@@ -244,6 +248,10 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
assert.strictEqual(typeof ledger.ledger_index, 'number');
this._pending.forEach(function(transaction) {
if (transaction.finalized) {
return;
}
switch (ledger.ledger_index - transaction.submitIndex) {
case 4:
transaction.emit('missing', ledger);
@@ -253,10 +261,6 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
break;
}
if (transaction.finalized) {
return;
}
if (ledger.ledger_index > transaction.tx_json.LastLedgerSequence) {
// Transaction must fail
transaction.emit('error', new RippleError(
@@ -265,46 +269,54 @@ TransactionManager.prototype._updatePendingStatus = function(ledger) {
});
};
//Fill an account transaction sequence
// Fill an account transaction sequence
TransactionManager.prototype._fillSequence = function(tx, callback) {
var self = this;
function submitFill(sequence, callback) {
var fill = self._remote.transaction();
fill.account_set(self._accountID);
fill.tx_json.Sequence = sequence;
fill.once('submitted', callback);
function submitFill(sequence, fCallback) {
var fillTransaction = self._remote.createTransaction('AccountSet', {
account: self._accountID
});
fillTransaction.tx_json.Sequence = sequence;
// Secrets may be set on a per-transaction basis
if (tx._secret) {
fill.secret(tx._secret);
fillTransaction.secret(tx._secret);
}
fill.submit();
};
fillTransaction.once('submitted', fCallback);
fillTransaction.submit();
}
function sequenceLoaded(err, sequence) {
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;
;(function nextFill(sequence) {
if (sequence >= tx.tx_json.Sequence) {
return;
}
submitFill(sequence, function() {
if (++submitted === sequenceDif) {
async.whilst(
function() {
return submitted < sequenceDiff;
},
function(asyncCallback) {
submitFill(sequence, function(res) {
++submitted;
if (res.engine_result === 'tesSUCCESS') {
self.emit('sequence_filled', err);
}
asyncCallback();
});
},
function() {
if (callback) {
callback();
} else {
nextFill(sequence + 1);
}
});
})(sequence);
};
}
);
}
this._loadSequence(sequenceLoaded);
};
@@ -318,7 +330,7 @@ TransactionManager.prototype._fillSequence = function(tx, callback) {
TransactionManager.prototype._loadSequence = function(callback) {
var self = this;
var callback = (typeof callback === 'function') ? callback : function(){};
callback = (typeof callback === 'function') ? callback : function() {};
function sequenceLoaded(err, sequence) {
if (err || typeof sequence !== 'number') {
@@ -331,7 +343,7 @@ TransactionManager.prototype._loadSequence = function(callback) {
self._nextSequence = sequence;
self.emit('sequence_loaded', sequence);
callback(err, sequence);
};
}
this._account.getNextSequence(sequenceLoaded);
};
@@ -346,10 +358,11 @@ TransactionManager.prototype._loadSequence = function(callback) {
TransactionManager.prototype._handleReconnect = function(callback) {
var self = this;
var callback = (typeof callback === 'function') ? callback : function(){};
callback = (typeof callback === 'function') ? callback : function() {};
if (!this._pending.length()) {
return callback();
callback();
return;
}
function handleTransactions(err, transactions) {
@@ -372,7 +385,7 @@ TransactionManager.prototype._handleReconnect = function(callback) {
// Resubmit pending transactions after sequence is loaded
self._resubmit();
});
};
}
var options = {
account: this._accountID,
@@ -410,7 +423,7 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
self._remote.removeListener('ledger_closed', ledgerClosed);
callback();
}
};
}
this._remote.on('ledger_closed', ledgerClosed);
};
@@ -426,8 +439,16 @@ TransactionManager.prototype._waitLedgers = function(ledgers, callback) {
TransactionManager.prototype._resubmit = function(ledgers, pending) {
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) {
if (!transaction || transaction.finalized) {
@@ -439,11 +460,17 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
var received = transaction.findId(self._pending._idCache);
if (received) {
return transaction.emit('success', received);
switch (received.engine_result) {
case 'tesSUCCESS':
transaction.emit('success', received);
break;
default:
transaction.emit('error', received);
}
}
while (self._pending.hasSequence(transaction.tx_json.Sequence)) {
//Sequence number has been consumed by another transaction
// Sequence number has been consumed by another transaction
transaction.tx_json.Sequence += 1;
if (self._remote.trace) {
@@ -461,7 +488,7 @@ TransactionManager.prototype._resubmit = function(ledgers, pending) {
});
self._request(transaction);
};
}
this._waitLedgers(ledgers, function() {
async.eachSeries(pending, resubmitTransaction);
@@ -522,8 +549,8 @@ TransactionManager.prototype._request = function(tx) {
}
if (tx.attempts > 0 && !remote.local_signing) {
var message = 'Automatic resubmission requires local signing';
tx.emit('error', new RippleError('tejLocalSigningRequired', message));
var errMessage = 'Automatic resubmission requires local signing';
tx.emit('error', new RippleError('tejLocalSigningRequired', errMessage));
return;
}
@@ -536,22 +563,22 @@ TransactionManager.prototype._request = function(tx) {
// Transaction may succeed after Sequence is updated
self._resubmit(1, tx);
}
};
}
function transactionRetry(message) {
function transactionRetry() {
// XXX This may no longer be necessary. Instead, update sequence numbers
// after a transaction fails definitively
self._fillSequence(tx, function() {
self._resubmit(1, tx);
});
};
}
function transactionFailedLocal(message) {
if (message.engine_result === 'telINSUF_FEE_P') {
// Transaction may succeed after Fee is updated
self._resubmit(1, tx);
}
};
}
function submissionError(error) {
// Either a tem-class error or generic server error such as tooBusy. This
@@ -562,7 +589,7 @@ TransactionManager.prototype._request = function(tx) {
self._nextSequence--;
tx.emit('error', error);
}
};
}
function submitted(message) {
if (tx.finalized) {
@@ -605,7 +632,7 @@ TransactionManager.prototype._request = function(tx) {
// tem
submissionError(message);
}
};
}
function requestTimeout() {
// 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);
}
};
}
tx.submitIndex = this._remote._ledger_current_index;
@@ -655,10 +682,7 @@ TransactionManager.prototype._request = function(tx) {
tx.emit('postsubmit');
//XXX
submitRequest.timeout(self._submissionTimeout, requestTimeout);
return submitRequest;
};
/**
@@ -669,7 +693,6 @@ TransactionManager.prototype._request = function(tx) {
TransactionManager.prototype.submit = function(tx) {
var self = this;
var remote = this._remote;
if (typeof this._nextSequence !== 'number') {
// If sequence number is not yet known, defer until it is.

View File

@@ -1,3 +1,6 @@
'use strict';
var lodash = require('lodash');
var LRU = require('lru-cache');
var Transaction = require('./transaction').Transaction;
@@ -7,9 +10,9 @@ var Transaction = require('./transaction').Transaction;
function TransactionQueue() {
this._queue = [ ];
this._idCache = LRU({ max: 200 });
this._sequenceCache = LRU({ max: 200 });
};
this._idCache = new LRU({max: 200});
this._sequenceCache = new LRU({max: 200});
}
/**
* Store received (validated) sequence
@@ -64,16 +67,9 @@ TransactionQueue.prototype.getReceived = function(id) {
*/
TransactionQueue.prototype.getSubmission = function(id) {
var result = void(0);
for (var i=0, tx; (tx=this._queue[i]); i++) {
if (~tx.submittedIDs.indexOf(id)) {
result = tx;
break;
}
}
return result;
return lodash.find(this._queue, function(tx) {
return lodash.contains(tx.submittedIDs, id);
});
};
/**
@@ -83,11 +79,15 @@ TransactionQueue.prototype.getSubmission = function(id) {
*/
TransactionQueue.prototype.getMinLedger = function() {
if (this.length() < 1) {
return -1;
}
var result = Infinity;
for (var i=0, tx; (tx=this._queue[i]); i++) {
if (tx.initialSubmitIndex < result) {
result = tx.initialSubmitIndex;
for (var i = 0; i < this.length(); i++) {
if (this._queue[i].initialSubmitIndex < result) {
result = this._queue[i].initialSubmitIndex;
}
}
@@ -153,4 +153,12 @@ TransactionQueue.prototype.getLength = function() {
return this._queue.length;
};
/**
* @return {Array} pending queue
*/
TransactionQueue.prototype.getQueue = function() {
return this._queue;
};
exports.TransactionQueue = TransactionQueue;

View File

@@ -2,8 +2,6 @@ var utils = require('./utils');
var sjcl = utils.sjcl;
var config = require('./config');
var BigInteger = utils.jsbn.BigInteger;
//
// Abstract UInt class
//
@@ -11,7 +9,7 @@ var BigInteger = utils.jsbn.BigInteger;
//
var UInt = function() {
// Internal form: NaN or BigInteger
// Internal form: NaN or sjcl.bn
this._value = NaN;
this._update();
};
@@ -107,17 +105,15 @@ UInt.prototype.copyTo = function(d) {
};
UInt.prototype.equals = function(d) {
return this._value instanceof BigInteger
&& d._value instanceof BigInteger
&& this._value.equals(d._value);
return this.is_valid() && d.is_valid() && this._value.equals(d._value);
};
UInt.prototype.is_valid = function() {
return this._value instanceof BigInteger;
return this._value instanceof sjcl.bn;
};
UInt.prototype.is_zero = function() {
return this._value.equals(BigInteger.ZERO);
return this.is_valid() && this._value.equals(new sjcl.bn(0));
};
/**
@@ -147,24 +143,25 @@ UInt.prototype.parse_generic = function(j) {
case this.constructor.STR_ZERO:
case this.constructor.ACCOUNT_ZERO:
case this.constructor.HEX_ZERO:
this._value = BigInteger.valueOf();
this._value = new sjcl.bn(0);
break;
case '1':
case this.constructor.STR_ONE:
case this.constructor.ACCOUNT_ONE:
case this.constructor.HEX_ONE:
this._value = new BigInteger([1]);
this._value = new sjcl.bn(1);
break;
default:
if (typeof j !== 'string') {
this._value = NaN;
} 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) {
// XXX Check char set!
this._value = new BigInteger(j, 16);
this._value = new sjcl.bn(j, 16);
} else {
this._value = NaN;
}
@@ -177,7 +174,7 @@ UInt.prototype.parse_generic = function(j) {
UInt.prototype.parse_hex = function(j) {
if (typeof j === 'string' && j.length === (this.constructor.width * 2)) {
this._value = new BigInteger(j, 16);
this._value = new sjcl.bn(j, 16);
} else {
this._value = NaN;
}
@@ -191,8 +188,9 @@ UInt.prototype.parse_bits = function(j) {
if (sjcl.bitArray.bitLength(j) !== this.constructor.width * 8) {
this._value = NaN;
} else {
var bytes = sjcl.codec.bytes.fromBits(j);
this.parse_bytes(bytes);
this._value = sjcl.bn.fromBits(j);
// var bytes = sjcl.codec.bytes.fromBits(j);
// this.parse_bytes(bytes);
}
this._update();
@@ -205,7 +203,8 @@ UInt.prototype.parse_bytes = function(j) {
if (!Array.isArray(j) || j.length !== this.constructor.width) {
this._value = NaN;
} else {
this._value = new BigInteger([0].concat(j), 256);
var bits = sjcl.codec.bytes.toBits(j);
this._value = sjcl.bn.fromBits(bits);
}
this._update();
@@ -218,8 +217,9 @@ UInt.prototype.parse_json = UInt.prototype.parse_hex;
UInt.prototype.parse_bn = function(j) {
if ((j instanceof sjcl.bn) && j.bitLength() <= this.constructor.width * 8) {
var bytes = sjcl.codec.bytes.fromBits(j.toBits());
this._value = new BigInteger(bytes, 256);
// var bytes = sjcl.codec.bytes.fromBits(j.toBits());
// this._value = new sjcl.bn(utils.arrayToHex(bytes), 16);
this._value = new sjcl.bn(j);
} else {
this._value = NaN;
}
@@ -233,7 +233,7 @@ UInt.prototype.parse_number = function(j) {
this._value = NaN;
if (typeof j === 'number' && isFinite(j) && j >= 0) {
this._value = new BigInteger(String(j));
this._value = new sjcl.bn(j);
}
this._update();
@@ -243,51 +243,31 @@ UInt.prototype.parse_number = function(j) {
// Convert from internal form.
UInt.prototype.to_bytes = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}
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;
return sjcl.codec.bytes.fromBits(this.to_bits());
};
UInt.prototype.to_hex = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}
var bytes = this.to_bytes();
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(bytes)).toUpperCase();
return sjcl.codec.hex.fromBits(this.to_bits()).toUpperCase();
};
UInt.prototype.to_json = UInt.prototype.to_hex;
UInt.prototype.to_bits = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}
var bytes = this.to_bytes();
return sjcl.codec.bytes.toBits(bytes);
return this._value.toBits(this.constructor.width * 8);
};
UInt.prototype.to_bn = function() {
if (!(this._value instanceof BigInteger)) {
if (!this.is_valid()) {
return null;
}

View File

@@ -7,7 +7,6 @@ var UInt = require('./uint').UInt;
//
var UInt128 = extend(function () {
// Internal form: NaN or BigInteger
this._value = NaN;
}, UInt);

View File

@@ -2,8 +2,6 @@ var utils = require('./utils');
var config = require('./config');
var extend = require('extend');
var BigInteger = utils.jsbn.BigInteger;
var UInt = require('./uint').UInt;
var Base = require('./base').Base;
@@ -12,7 +10,6 @@ var Base = require('./base').Base;
//
var UInt160 = extend(function() {
// Internal form: NaN or BigInteger
this._value = NaN;
this._version_byte = void(0);
this._update();
@@ -49,7 +46,7 @@ UInt160.prototype.parse_json = function(j) {
// Allow raw numbers - DEPRECATED
// This is used mostly by the test suite and is supported
// as a legacy feature only. DO NOT RELY ON THIS BEHAVIOR.
this._value = new BigInteger(String(j));
this.parse_number(j);
this._version_byte = Base.VER_ACCOUNT_ID;
} else if (typeof j !== 'string') {
this._value = NaN;
@@ -83,7 +80,7 @@ UInt160.prototype.parse_generic = function(j) {
UInt160.prototype.to_json = function(opts) {
opts = opts || {};
if (this._value instanceof BigInteger) {
if (this.is_valid()) {
// If this value has a type, return a Base58 encoded string.
if (typeof this._version_byte === 'number') {
var output = Base.encode_check(this._version_byte, this.to_bytes());

View File

@@ -7,7 +7,6 @@ var UInt = require('./uint').UInt;
//
var UInt256 = extend(function() {
// Internal form: NaN or BigInteger
this._value = NaN;
}, UInt);

View File

@@ -1,3 +1,15 @@
function getMantissaDecimalString(bignum) {
var mantissa = bignum.toPrecision(16)
.replace(/\./, '') // remove decimal point
.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;
}
function filterErr(code, done) {
return function(e) {
done(e.code !== code ? e : void(0));
@@ -69,6 +81,13 @@ function hexToArray(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) {
var ret = [];
var i=0, len=str.length;
@@ -144,15 +163,16 @@ exports.hexToString = hexToString;
exports.hexToArray = hexToArray;
exports.stringToArray = stringToArray;
exports.stringToHex = stringToHex;
exports.arrayToHex = arrayToHex;
exports.chunkString = chunkString;
exports.assert = assert;
exports.arrayUnique = arrayUnique;
exports.toTimestamp = toTimestamp;
exports.fromTimestamp = fromTimestamp;
exports.getMantissaDecimalString = getMantissaDecimalString;
// Going up three levels is needed to escape the src-cov folder used for the
// test coverage stuff.
exports.sjcl = require('../../../build/sjcl');
exports.jsbn = require('../../../src/js/jsbn/jsbn');
// vim:sw=2:sts=2:ts=8:et

View File

@@ -1,5 +1,4 @@
var assert = require('assert');
var BigInteger = require('ripple-lib').jsbn.BigInteger;
var Amount = require('ripple-lib').Amount;
var UInt160 = require('ripple-lib').UInt160;
var load_config = require('ripple-lib').config.load;
@@ -121,12 +120,21 @@ describe('Amount', 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() {
assert.strictEqual(Amount.from_human("1 XRP").to_text_full(), '1/XRP');
});
it('1 XRP human', function() {
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() {
assert.strictEqual(Amount.from_human("0.1 XRP").to_text_full(), '0.1/XRP');
});
@@ -281,14 +289,11 @@ describe('Amount', function() {
});
});
describe('UInt160', function() {
it('Parse 0', function () {
assert.deepEqual(new BigInteger(), UInt160.from_generic('0')._value);
});
it('Parse 0 export', function () {
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_generic('0').set_version(0).to_json());
});
it('Parse 1', function () {
assert.deepEqual(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 () {
assert.strictEqual(UInt160.ACCOUNT_ZERO, UInt160.from_json('rrrrrrrrrrrrrrrrrrrrrhoLvTp').to_json());
@@ -331,9 +336,9 @@ describe('Amount', function() {
});
describe('Amount parsing', function() {
it('Parse invalid string', function() {
assert.strictEqual(Amount.from_json('x').to_text(), '0');
assert.strictEqual(typeof Amount.from_json('x').to_text(true), 'number');
assert(isNaN(Amount.from_json('x').to_text(true)));
assert.strictEqual(Amount.from_json('x').to_text(), 'NaN');
assert.strictEqual(typeof Amount.from_json('x').to_text(), 'string');
assert(isNaN(Amount.from_json('x').to_text()));
});
it('parse dem', function() {
assert.strictEqual(Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full(), '10/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
@@ -357,22 +362,26 @@ describe('Amount', function() {
assert.strictEqual('0/XRP', Amount.from_json('0').to_text_full());
});
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 () {
assert.strictEqual('0/XRP', Amount.from_json('-0').to_text_full());
});
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 () {
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_text_full());
});
it('Parse native 12.3', function () {
assert.strictEqual('12.3/XRP', Amount.from_json('12.3').to_text_full());
it('Parse native 12300000', function () {
assert.strictEqual('12.3/XRP', Amount.from_json('12300000').to_text_full());
});
it('Parse native -12.3', function () {
assert.strictEqual('-12.3/XRP', Amount.from_json('-12.3').to_text_full());
it('Parse native -12300000', function () {
assert.strictEqual('-12.3/XRP', Amount.from_json('-12300000').to_text_full());
});
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
@@ -401,23 +410,17 @@ describe('Amount', function() {
it('Parse native 0 human', function () {
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 () {
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 () {
assert.strictEqual('0.001/XRP', Amount.from_json('1000').to_human_full());
});
it('Parse native 12.3 human', function () {
assert.strictEqual('12.3/XRP', Amount.from_json('12.3').to_human_full());
it('Parse native 12300000 human', function () {
assert.strictEqual('12.3/XRP', Amount.from_json('12300000').to_human_full());
});
it('Parse native -12.3 human', function () {
assert.strictEqual('-12.3/XRP', Amount.from_json('-12.3').to_human_full());
it('Parse native -12300000 human', function () {
assert.strictEqual('-12.3/XRP', Amount.from_json('-12300000').to_human_full());
});
it('Parse 123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh human', function () {
assert.strictEqual('123/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('123./USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
@@ -785,7 +788,7 @@ describe('Amount', function() {
});
it('0 XRP == 0 XRP', function () {
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.not_equals_why(b));
});
@@ -814,8 +817,8 @@ describe('Amount', function() {
assert(!a.not_equals_why(b));
});
it('1.1 XRP == 1.1 XRP', function () {
var a = Amount.from_json('1.1');
var b = Amount.from_json('11.0').ratio_human(10);
var a = Amount.from_json('1100000');
var b = Amount.from_json('11000000').ratio_human('10/XRP');
assert(a.equals(b));
assert(!a.not_equals_why(b));
});
@@ -973,7 +976,7 @@ describe('Amount', function() {
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 () {
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 () {
assert.strictEqual('0/XRP', Amount.from_json('0').product_human(Amount.from_json('0')).to_human_full());
@@ -1045,7 +1048,7 @@ describe('Amount', function() {
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 () {
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');
});
});
@@ -1080,6 +1083,11 @@ describe('Amount', 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 () {
assert.strictEqual(Amount.from_quality('7B73A610A009249B0CC0D4311E8BA7927B5A34D86634581C5F0FF9FF678E1000', 'XRP', NaN, {base_currency: 'BTC'}).to_text_full(), '44,970/XRP');
});
@@ -1183,11 +1191,11 @@ describe('Amount', function() {
describe('amount limits', 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() {
assert.strictEqual(Amount.bi_xns_min.toString(), '-9000000000000000000');
assert.strictEqual(Amount.bi_xns_min.toString(), '-100000000000000000');
});
it('max mantissa value', function() {
@@ -1199,28 +1207,29 @@ describe('Amount', function() {
});
it ('from_json minimum XRP', function() {
var amt = Amount.from_json('-9000000000000000000');
assert.strictEqual(amt.to_json(), '-9000000000000000000');
var amt = Amount.from_json('-100000000000000000');
assert.strictEqual(amt.to_json(), '-100000000000000000');
});
it ('from_json maximum XRP', function() {
var amt = Amount.from_json('-9000000000000000000');
assert.strictEqual(amt.to_json(), '-9000000000000000000');
var amt = Amount.from_json('100000000000000000');
assert.strictEqual(amt.to_json(), '100000000000000000');
});
it ('from_json less than minimum XRP', function() {
var amt = Amount.from_json('-9000000000000000001');
assert.strictEqual(amt.to_json(), '0');
assert.throws(function() {
Amount.from_json('-100000000000000001');
});
});
it ('from_json more than maximum XRP', function() {
var amt = Amount.from_json('9000000000000000001');
assert.strictEqual(amt.to_json(), '0');
assert.throws(function() {
Amount.from_json('100000000000000001');
});
});
it ('from_json minimum IOU', function() {
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(), Amount.min_value);
});
@@ -1233,7 +1242,6 @@ describe('Amount', function() {
it ('from_json maximum IOU', function() {
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');
});
@@ -1245,13 +1253,11 @@ describe('Amount', function() {
it ('from_json normalize mantissa to valid max range, lost significant digits', function() {
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');
});
it ('from_json normalize mantissa to min valid range, lost significant digits', function() {
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');
});
});

66
test/base-test.js Normal file
View 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));
}
});
});
});

View File

@@ -1,17 +0,0 @@
var assert = require('assert');
var Seed = require('ripple-lib').Seed;
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

View 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);
});
});

View File

@@ -1,3 +1,5 @@
/*eslint-disable */
var assert = require('assert');
var currency = require('ripple-lib').Currency;
var timeUtil = require('ripple-lib').utils.time;
@@ -54,6 +56,16 @@ describe('Currency', function() {
assert(r.is_valid());
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() {
var r = currency.from_json("XAU");
assert.strictEqual('0000000000000000000000005841550000000000', r.to_json({force_hex: true}));

5
test/fixtures/addresses.js vendored Normal file
View 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
View 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"
}
]
}

View 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
View 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"
}
}
}

File diff suppressed because it is too large Load Diff

857
test/fixtures/orderbook.js vendored Normal file
View 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
View 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"
}

View 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
View 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
View 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
View 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"
}
}

View File

@@ -33,5 +33,4 @@ describe('Meta', function() {
assert.strictEqual(meta.nodes[idx], curr);
}, []);
});
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -726,6 +726,16 @@ describe('Request', function() {
assert.strictEqual(request.message.ledger_hash, void(0));
});
it('Select ledger - index (String)', function() {
var remote = new Remote();
remote._connected = true;
var request = new Request(remote, 'server_info');
request.ledgerSelect('7016915');
assert.strictEqual(request.message.ledger_index, 7016915);
assert.strictEqual(request.message.ledger_hash, void(0));
});
it('Select ledger - hash', function() {
var remote = new Remote();
remote._connected = true;

View File

@@ -1,41 +1,51 @@
/* eslint max-len: 0 */
'use strict';
var assert = require('assert');
var Seed = require('ripple-lib').Seed;
var Seed = require('ripple-lib').Seed;
function assert_helper(seed_json, address_or_nth, expected) {
var seed = Seed.from_json(seed_json);
var keypair = seed.get_key(address_or_nth, 500);
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"]
['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) {
var seed = Seed.from_json(seed_json);
var keypair = seed.get_key(address_or_nth, 500);
assert.strictEqual(keypair.to_hex_pub(), expected);
}
for (var nth = 0; nth < test_data.length; nth++) {
var seed_json = test_data[nth][0];
var address = test_data[nth][1];
var nth_for_seed = test_data[nth][2];
var expected = test_data[nth][3];
//`seed.get_key($ripple_address)` is arguably an ill concieved feature
// `seed.get_key($ripple_address)` is arguably an ill concieved feature
// as it needs to generate `nth` many keypairs and generate hashed public
// keys (addresses) for equality tests ??
// Would need remote.set_secret(address, private_key_not_seed) ??
@@ -43,7 +53,7 @@ describe('Seed', function() {
// This isn't too bad as it only needs to generate one keypair `seq`
assert_helper(seed_json, nth_for_seed, expected);
};
}
});
@@ -63,7 +73,7 @@ describe('Seed', function() {
seed.get_key(address);
assert(false, 'should throw an error');
} catch(e) {
assert.strictEqual(e.message, 'Too many loops looking for KeyPair yielding '+address+' from '+secret);
assert.strictEqual(e.message, 'Too many loops looking for KeyPair yielding ' + address + ' from ' + secret);
}
});

View File

@@ -1,6 +1,20 @@
var assert = require('assert');
'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 SerializedObject = require('ripple-lib').SerializedObject;
var sjcl = require('ripple-lib').sjcl;
var Amount = require('ripple-lib').Amount;
var sjcl = require('ripple-lib').sjcl;
// Shortcuts
var hex = sjcl.codec.hex;
@@ -29,10 +43,14 @@ describe('Serialized object', function() {
{
account: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
currency: 'USD',
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV'
issuer: 'r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV',
type: 49,
type_hex: "0000000000000031"
},
{
currency: 'XRP'
currency: 'XRP',
type: 16,
type_hex: "0000000000000010"
}
]],
SendMax: {
@@ -50,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() {
it('understands TransactionType as a Number', function() {
var input_json = {
@@ -105,7 +173,6 @@ describe('Serialized object', function() {
});
describe('Memos', function() {
var input_json;
beforeEach(function() {
@@ -126,10 +193,10 @@ describe('Serialized object', function() {
it('should serialize and parse - full memo, all strings text/plain ', function() {
input_json.Memos = [
{
"Memo": {
"MemoType": "test",
"MemoFormat": "text",
"MemoData": "some data"
Memo: {
MemoType: '74657374',
MemoFormat: '74657874',
MemoData: '736F6D652064617461'
}
}
];
@@ -148,10 +215,11 @@ describe('Serialized object', function() {
it('should serialize and parse - full memo, all strings, invalid MemoFormat', function() {
input_json.Memos = [
{
"Memo": {
"MemoType": "test",
"MemoFormat": "application/json",
"MemoData": "some data"
"Memo":
{
MemoType: '74657374',
MemoFormat: '6170706C69636174696F6E2F6A736F6E',
MemoData: '736F6D652064617461'
}
}
];
@@ -167,36 +235,14 @@ describe('Serialized object', function() {
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() {
input_json.Memos = [
{
"Memo": {
"MemoType": "test",
"MemoFormat": "json",
"ignored" : "ignored",
"MemoData": {
"string" : "some_string",
"boolean" : true
}
Memo: {
MemoType: '74657374',
MemoFormat: '6A736F6E',
ignored : 'ignored',
MemoData: '7B22737472696E67223A22736F6D655F737472696E67222C22626F6F6C65616E223A747275657D'
}
}
];
@@ -221,79 +267,25 @@ describe('Serialized object', function() {
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() {
input_json.Memos = [
{
"Memo": {
"MemoType": "test",
"MemoParty": "json",
"MemoData": 3
Memo: {
MemoType: '74657374',
MemoField: '6A736F6E',
MemoData: '7B22737472696E67223A22736F6D655F737472696E67222C22626F6F6C65616E223A747275657D'
}
}
];
assert.throws(function() {
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() {
var input_json = {
input_json = {
Flags: 2147483648,
TransactionType: 'Payment',
Account: 'rhXzSyt1q9J8uiFXpK3qSugAAPJKXLtnrF',
@@ -302,7 +294,7 @@ describe('Serialized object', function() {
Memos: [
{
Memo: {
MemoType: 'image'
MemoType: '696D616765'
}
}
],

View File

@@ -2,7 +2,7 @@ var assert = require('assert');
var SerializedObject = require('ripple-lib').SerializedObject;
var types = require('ripple-lib').types;
var Amount = require('ripple-lib').Amount;
var BigInteger = require('ripple-lib').jsbn.BigInteger;
var sjcl = require('ripple-lib').sjcl;
describe('Serialized types', function() {
describe('Int8', function() {
@@ -287,7 +287,7 @@ describe('Serialized types', function() {
var so = new SerializedObject("8B2386F26F8E232B");
var num = types.Int64.parse(so);
// We get a positive number
assert.strictEqual(num.toString(16), '8b2386f26f8e232b');
assert.strictEqual(num.toString(), '0x8b2386f26f8e232b');
});
it('Serialize "0123456789ABCDEF"', function () {
var so = new SerializedObject();
@@ -299,15 +299,15 @@ describe('Serialized types', function() {
types.Int64.serialize(so, 'F0E1D2C3B4A59687');
assert.strictEqual(so.to_hex(), 'F0E1D2C3B4A59687');
});
it('Serialize BigInteger("FFEEDDCCBBAA9988")', function () {
it('Serialize bn("FFEEDDCCBBAA9988")', function () {
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');
});
it('Fail to serialize BigInteger("-1")', function () {
it('Fail to serialize BigNumber("-1")', function () {
var so = new SerializedObject();
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 () {
@@ -343,7 +343,7 @@ describe('Serialized types', function() {
it('Parse "0123456789ABCDEF"', function () {
var so = new SerializedObject("0123456789ABCDEF");
var num = types.Int64.parse(so);
assert.strictEqual(num.toString(10), '81985529216486895');
assert.strictEqual(num.toString(), '0x123456789abcdef');
});
});
@@ -509,8 +509,10 @@ describe('Serialized types', function() {
});
it('Serialize 1161981756646125568 XRP', function () {
var so = new SerializedObject();
types.Amount.serialize(so, '1161981756646125696');
assert.strictEqual(so.to_hex(), '5020304050607080');
assert.throws(function() {
var amt = Amount.from_json('1161981756646125696');
types.Amount.serialize(so, amt);
});
});
it('Serialize 1/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
var so = new SerializedObject();
@@ -570,8 +572,11 @@ describe('Serialized types', function() {
assert.strictEqual(types.Amount.parse(so).to_json(), '270544960');
});
it('Parse 1161981756646125568 XRP', function () {
var so = new SerializedObject('5020304050607080');
assert.strictEqual(types.Amount.parse(so).to_json(), '1161981756646125696');
assert.throws(function() {
// hex(1161981756646125568) = 1020304050607000
var so = new SerializedObject('1020304050607000');
types.Amount.parse(so).to_json();
})
});
it('Parse 1/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
var so = new SerializedObject('D4838D7EA4C680000000000000000000000000005553440000000000B5F762798A53D543A014CAF8B297CFF8F2F937E8');
@@ -673,7 +678,7 @@ describe('Serialized types', function() {
it('Serialize path through XRP', function () {
var hex = '31000000000000000000000000000000000000007B00000000000000000000000055534400000000000000000000000000000000000000000000000315FF1000000000000000000000000000000000000000003100000000000000000000000000000000000003DB0000000000000000000000004555520000000000000000000000000000000000000000000000014100';
var json = [
[ {
[{
account: "rrrrrrrrrrrrrrrrrrrrNxV3Xza",
currency: 'USD',
issuer: "rrrrrrrrrrrrrrrrrrrpYnYCNYf"
@@ -687,18 +692,39 @@ describe('Serialized types', function() {
}]
];
var result_json = [
[{
account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
currency: 'USD',
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
type: 49,
type_hex: '0000000000000031'
}],
[{
currency: 'XRP',
type: 16,
type_hex: '0000000000000010'
}, {
account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
currency: 'EUR',
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2',
type: 49,
type_hex: '0000000000000031'
}]
];
var so = new SerializedObject();
types.PathSet.serialize(so, json);
assert.strictEqual(so.to_hex(), hex);
so = new SerializedObject(hex);
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
assert.deepEqual(parsed_path, json);
assert.deepEqual(parsed_path, result_json);
});
it('Serialize path through XRP IOUs', function () {
var hex = '31000000000000000000000000000000000000007B00000000000000000000000055534400000000000000000000000000000000000000000000000315FF1000000000000000000000000058525000000000003100000000000000000000000000000000000003DB0000000000000000000000004555520000000000000000000000000000000000000000000000014100';
var json = [
[ {
[{
account: "rrrrrrrrrrrrrrrrrrrrNxV3Xza",
currency: 'USD',
issuer: "rrrrrrrrrrrrrrrrrrrpYnYCNYf"
@@ -713,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();
types.PathSet.serialize(so, json);
assert.strictEqual(so.to_hex(), hex);
so = new SerializedObject(hex);
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
assert.deepEqual(parsed_path, json);
assert.deepEqual(parsed_path, result_json);
});
it('Serialize path through XRP IOUs (realistic example)', function () {
// Appears in the history
@@ -778,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();
types.PathSet.serialize(so, json);
assert.strictEqual(so.to_hex(), hex);
so = new SerializedObject(hex);
var parsed_path = SerializedObject.jsonify_structure(types.PathSet.parse(so));
assert.deepEqual(parsed_path, json);
assert.deepEqual(parsed_path, result_json);
});
it('Parse single empty path [[]]', function () {
var so = new SerializedObject('00');
@@ -797,13 +919,20 @@ describe('Serialized types', function() {
var parsed_path = types.PathSet.parse(so);
var comp = [ [ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
currency: 'USD',
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf' } ],
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
type: 49,
type_hex: '0000000000000031' } ],
[ { account: 'rrrrrrrrrrrrrrrrrrrrNxV3Xza',
currency: 'BTC',
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf' },
issuer: 'rrrrrrrrrrrrrrrrrrrpYnYCNYf',
type: 49,
type_hex: '0000000000000031' },
{ account: 'rrrrrrrrrrrrrrrrrrrpvQsW3V3',
currency: 'EUR',
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2' } ] ];
issuer: 'rrrrrrrrrrrrrrrrrrrdHRtqg2',
type: 49,
type_hex: '0000000000000031' } ] ];
assert.deepEqual(SerializedObject.jsonify_structure(parsed_path, ""), comp);
});
});

View File

@@ -378,8 +378,6 @@ describe('Server', function() {
validated_ledgers: '32570-7053695'
}
}));
wss.close();
});
});
@@ -387,6 +385,7 @@ describe('Server', function() {
server.once('connect', function() {
server.once('disconnect', function() {
wss.close();
done();
});
server.disconnect();
@@ -442,8 +441,6 @@ describe('Server', function() {
validated_ledgers: '32570-7053695'
}
}));
wss.close();
});
});
@@ -451,6 +448,7 @@ describe('Server', function() {
server.once('connect', function() {
server.once('disconnect', function() {
wss.close();
done();
});
server.disconnect();
@@ -509,15 +507,16 @@ describe('Server', function() {
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() {
setImmediate(function() {
wss.close();
done();
});
};
@@ -554,8 +553,6 @@ describe('Server', function() {
server_status: 'syncing'
}
}));
wss.close();
});
});
@@ -567,6 +564,7 @@ describe('Server', function() {
assert.strictEqual(server._load_factor, 256);
assert.strictEqual(server._fee_base, 10);
assert.strictEqual(server._fee_ref, 10);
wss.close();
done();
});
@@ -1102,12 +1100,15 @@ describe('Server', function() {
case 'subscribe':
assert.strictEqual(m.command, 'subscribe');
assert.deepEqual(m.streams, [ 'ledger', 'server' ]);
sendSubscribe(m);
setImmediate(function() {
sendSubscribe(m);
});
break;
case 'server_info':
assert.strictEqual(m.command, 'server_info');
sendServerInfo(m);
wss.close();
setImmediate(function() {
sendServerInfo(m);
});
break;
}
});
@@ -1116,16 +1117,13 @@ describe('Server', function() {
var server = new Server(new Remote(), 'ws://localhost:5748');
server.once('connect', function() {
var receivedSubscribe = false;
server.once('response_server_info', function() {
receivedSubscribe = true;
});
server.once('disconnect', function() {
assert(receivedSubscribe);
assert.strictEqual(server.getServerID(), 'ws://localhost:5748 (n94pSqypSfddzAVj9qoezHyUoetsrMnwgNuBqRJ3WHvM8aMMf7rW)');
done();
server.once('disconnect', function() {
wss.close();
done();
});
server.disconnect();
});
});

View File

@@ -0,0 +1,630 @@
'use strict';
var ws = require('ws');
var lodash = require('lodash');
var assert = require('assert-diff');
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;
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) {
}
};
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();
});
});
});

View File

@@ -644,6 +644,83 @@ describe('Transaction', function() {
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() {
var input_json = {
Account : 'r4qLSAzv4LZ9TLsR7diphGwKnSEAMQTSjS',
@@ -1051,7 +1128,7 @@ describe('Transaction', function() {
transaction.tx_json.TransactionType = 'Payment';
var memoType = 'message';
var memoFormat = 'application/json';
var memoFormat = 'json';
var memoData = {
string: 'value',
bool: true,
@@ -1064,9 +1141,9 @@ describe('Transaction', function() {
{
Memo:
{
MemoType: memoType,
MemoFormat: memoFormat,
MemoData: memoData
MemoType: '6D657373616765',
MemoFormat: '6A736F6E',
MemoData: '7B22737472696E67223A2276616C7565222C22626F6F6C223A747275652C22696E7465676572223A317D'
}
}
];
@@ -1087,9 +1164,10 @@ describe('Transaction', function() {
var expected = [
{
Memo: {
MemoType: memo.memoType,
MemoData: memo.memoData
Memo:
{
MemoType: '74797065',
MemoData: '64617461'
}
}
];
@@ -1108,26 +1186,36 @@ describe('Transaction', function() {
transaction.addMemo('testkey4', 'text/html', '<html>');
var expected = [
{ Memo: {
MemoType: 'testkey',
MemoData: 'testvalue'
}},
{ Memo: {
MemoType: 'testkey2',
MemoData: 'testvalue2'
}},
{ Memo: {
MemoType: 'testkey3',
MemoFormat: 'text/html'
}},
{ Memo: {
MemoData: 'testvalue4'
}},
{ Memo: {
MemoType: 'testkey4',
MemoFormat: 'text/html',
MemoData: '<html>'
}}
{
Memo: {
MemoType: '746573746B6579',
MemoData: '7465737476616C7565'
}
},
{
Memo: {
MemoType: '746573746B657932',
MemoData: '7465737476616C756532'
}
},
{
Memo: {
MemoType: '746573746B657933',
MemoFormat: '746578742F68746D6C'
}
},
{
Memo: {
MemoData: '7465737476616C756534'
}
},
{
Memo: {
MemoType: '746573746B657934',
MemoFormat: '746578742F68746D6C',
MemoData: '3C68746D6C3E'
}
}
];
assert.deepEqual(transaction.tx_json.Memos, expected);
@@ -1178,7 +1266,7 @@ describe('Transaction', function() {
assert.deepEqual(transaction.tx_json.Memos, [
{
Memo: {
MemoData: 'some_string'
MemoData: '736F6D655F737472696E67'
}
}
]);
@@ -1189,6 +1277,7 @@ describe('Transaction', function() {
transaction.tx_json.TransactionType = 'Payment';
var memo = {
memoFormat: 'json',
memoData: {
string: 'string',
int: 1,
@@ -1208,7 +1297,8 @@ describe('Transaction', function() {
assert.deepEqual(transaction.tx_json.Memos, [
{
Memo: {
MemoData: memo.memoData
MemoFormat: '6A736F6E',
MemoData: '7B22737472696E67223A22737472696E67222C22696E74223A312C226172726179223A5B7B22737472696E67223A22737472696E67227D5D2C226F626A656374223A7B22737472696E67223A22737472696E67227D7D'
}
}
]);

View File

@@ -9,8 +9,8 @@ describe('UInt', function() {
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
});
it('should create 00000000000000000000000000000001 when called with 1', function () {
var val = UInt128.from_number(0);
assert.strictEqual(val.to_hex(), '00000000000000000000000000000000');
var val = UInt128.from_number(1);
assert.strictEqual(val.to_hex(), '00000000000000000000000000000001');
});
it('should create 000000000000000000000000FFFFFFFF when called with 0xFFFFFFFF', function () {
var val = UInt128.from_number(0xFFFFFFFF);