mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 02:55:50 +00:00
Revert "Ported declarative path tests to mocha"
This reverts commit abe4f1ba03.
This commit is contained in:
@@ -1,389 +0,0 @@
|
|||||||
################################### REQUIRES ###################################
|
|
||||||
|
|
||||||
# This gives coffee-script proper file/lines in the exceptions
|
|
||||||
|
|
||||||
async = require("async")
|
|
||||||
assert = require 'assert'
|
|
||||||
Amount = require("ripple-lib").Amount
|
|
||||||
Remote = require("ripple-lib").Remote
|
|
||||||
Seed = require("ripple-lib").Seed
|
|
||||||
Base = require("ripple-lib").Base
|
|
||||||
Transaction = require("ripple-lib").Transaction
|
|
||||||
sjcl = require("ripple-lib").sjcl
|
|
||||||
Server = require("./server").Server
|
|
||||||
testutils = require("./testutils")
|
|
||||||
|
|
||||||
#################################### HELPERS ###################################
|
|
||||||
|
|
||||||
pretty_json = (v) -> JSON.stringify(v, undefined, 2)
|
|
||||||
|
|
||||||
exports.TestAccount = class TestAccount
|
|
||||||
SHA256_RIPEMD160: (bits) ->
|
|
||||||
sjcl.hash.ripemd160.hash sjcl.hash.sha256.hash(bits)
|
|
||||||
|
|
||||||
get_address: (passphrase) ->
|
|
||||||
key_pair = Seed.from_json(passphrase).get_key()
|
|
||||||
pubKey = sjcl.codec.hex.toBits key_pair.to_hex_pub()
|
|
||||||
Base.encode_check(0,sjcl.codec.bytes.fromBits(@SHA256_RIPEMD160 pubKey))
|
|
||||||
|
|
||||||
constructor: (passphrase) ->
|
|
||||||
@passphrase = passphrase
|
|
||||||
@address = @get_address(passphrase)
|
|
||||||
|
|
||||||
############################# LEDGER STATE COMPILER ############################
|
|
||||||
|
|
||||||
exports.LedgerState = class LedgerState
|
|
||||||
setup_issuer_realiaser: ->
|
|
||||||
users = @config.accounts
|
|
||||||
lookup = {}
|
|
||||||
accounts = []
|
|
||||||
|
|
||||||
for name, user of users
|
|
||||||
accounts.push user.account
|
|
||||||
lookup[user.account] = name
|
|
||||||
|
|
||||||
realias = new RegExp(accounts.join("|"), "g")
|
|
||||||
@realias_issuer = (str) -> str.replace(realias, (match) ->lookup[match])
|
|
||||||
|
|
||||||
parse_amount: (amt_val) ->
|
|
||||||
try
|
|
||||||
amt = Amount.from_json(amt_val)
|
|
||||||
if not amt.is_valid()
|
|
||||||
throw new Error()
|
|
||||||
catch e
|
|
||||||
try
|
|
||||||
amt = Amount.from_human(amt_val)
|
|
||||||
if not amt.is_valid()
|
|
||||||
throw new Error()
|
|
||||||
catch e
|
|
||||||
amt = null
|
|
||||||
amt
|
|
||||||
|
|
||||||
amount_key: (amt) ->
|
|
||||||
currency = amt.currency().to_json()
|
|
||||||
issuer = @realias_issuer amt.issuer().to_json()
|
|
||||||
key = "#{currency}/#{issuer}"
|
|
||||||
key.issuer = issuer
|
|
||||||
key
|
|
||||||
|
|
||||||
apply: (context)->
|
|
||||||
@create_accounts_by_issuing_xrp_from_root(context)
|
|
||||||
@create_trust_limits(context)
|
|
||||||
@deliver_ious(context)
|
|
||||||
|
|
||||||
record_iou: (account_id, amt)->
|
|
||||||
key = @amount_key amt
|
|
||||||
@assert @declaration.accounts[key.split('/')[1]]?,
|
|
||||||
"Account for #{key} does not exist"
|
|
||||||
|
|
||||||
a_ious = @ensure account_id, @ious
|
|
||||||
@assert !a_ious[key]?,
|
|
||||||
"Account #{account_id} has more than one amount for #{key}"
|
|
||||||
a_ious[key] = amt
|
|
||||||
|
|
||||||
ensure: (account_id, obj, val) ->
|
|
||||||
if not obj[account_id]?
|
|
||||||
obj[account_id] = val ? {}
|
|
||||||
obj[account_id]
|
|
||||||
|
|
||||||
record_xrp: (account_id, amt)->
|
|
||||||
@assert !@accounts[account_id]?,
|
|
||||||
"Already declared XRP for #{account_id}"
|
|
||||||
@accounts[account_id] = amt
|
|
||||||
|
|
||||||
record_trust: (account_id, amt, is_balance) ->
|
|
||||||
key = @amount_key amt
|
|
||||||
a_trusts = @ensure account_id, @trusts_by_ci
|
|
||||||
|
|
||||||
if a_trusts[key]? and !is_balance
|
|
||||||
cmp = amt.compareTo a_trusts[key]
|
|
||||||
@assert cmp != - 1,
|
|
||||||
"Account #{account_id} trust is less than balance for #{key}"
|
|
||||||
a_trusts[key] = amt
|
|
||||||
|
|
||||||
compile_explicit_trusts: ->
|
|
||||||
for account_id, account of @declaration.accounts
|
|
||||||
if not account.trusts?
|
|
||||||
continue
|
|
||||||
|
|
||||||
for amt_val in account.trusts
|
|
||||||
amt = @parse_amount amt_val
|
|
||||||
@assert amt != null and !amt.is_native(),
|
|
||||||
"Trust amount #{amt_val} specified for #{account_id} is not valid"
|
|
||||||
@record_trust(account_id, amt, false)
|
|
||||||
|
|
||||||
compile_accounts_balances_and_implicit_trusts: ->
|
|
||||||
for account_id, account of @declaration.accounts
|
|
||||||
xrp_balance = null
|
|
||||||
|
|
||||||
@assert account.balance?,
|
|
||||||
"No balance declared for #{account_id}"
|
|
||||||
|
|
||||||
for amt_val in account.balance
|
|
||||||
amt = @parse_amount amt_val
|
|
||||||
@assert amt != null,
|
|
||||||
"Balance amount #{amt_val} specified for #{account_id} is not valid"
|
|
||||||
|
|
||||||
if amt.is_native()
|
|
||||||
xrp_balance = @record_xrp(account_id, amt)
|
|
||||||
else
|
|
||||||
@record_iou(account_id, amt)
|
|
||||||
@record_trust(account_id, amt, true)
|
|
||||||
|
|
||||||
@assert xrp_balance,
|
|
||||||
"No XRP balanced declared for #{account_id}"
|
|
||||||
|
|
||||||
compile_offers: ->
|
|
||||||
for account_id, account of @declaration.accounts
|
|
||||||
if not account.offers?
|
|
||||||
continue
|
|
||||||
for offer in account.offers
|
|
||||||
[pays, gets, splat...] = offer
|
|
||||||
gets_amt = @parse_amount gets
|
|
||||||
@assert gets_amt != null,
|
|
||||||
"For account #{account_id} taker_gets amount #{gets} is invalid"
|
|
||||||
|
|
||||||
pays_amt = @parse_amount pays
|
|
||||||
@assert pays_amt != null,
|
|
||||||
"For account #{account_id} taker_pays amount #{pays} is invalid"
|
|
||||||
|
|
||||||
a_offers = @ensure(account_id, @offers_by_ci)
|
|
||||||
a_offers = @ensure(account_id, @offers_by_ci)
|
|
||||||
offers_all = @ensure('offers', a_offers, [])
|
|
||||||
|
|
||||||
if gets_amt.is_native()
|
|
||||||
total = a_offers.xrp_total ?= new Amount.from_json('0')
|
|
||||||
new_total = total.add(gets_amt)
|
|
||||||
@assert @accounts[account_id].compareTo(new_total) != - 1,
|
|
||||||
"Account #{account_id}s doesn't have enough xrp to place #{offer}"
|
|
||||||
else
|
|
||||||
key = @amount_key gets_amt
|
|
||||||
key_offers = @ensure(key, a_offers, {})
|
|
||||||
|
|
||||||
total = key_offers.total ?= Amount.from_json("0/#{key}")
|
|
||||||
new_total = total.add(gets_amt)
|
|
||||||
a_ious = @ensure(account_id, @ious)
|
|
||||||
@assert a_ious[key]?,
|
|
||||||
"Account #{account_id} doesn't hold any #{key}"
|
|
||||||
@assert a_ious[key].compareTo(new_total) != - 1,
|
|
||||||
"Account #{account_id} doesn't have enough #{key} to place #{offer}"
|
|
||||||
|
|
||||||
key_offers.total = new_total
|
|
||||||
|
|
||||||
offers_all.push [pays_amt, gets_amt, splat...]
|
|
||||||
|
|
||||||
@offers = []
|
|
||||||
for account_id, obj of @offers_by_ci
|
|
||||||
for offer in obj.offers
|
|
||||||
sliced = offer[0..]
|
|
||||||
sliced.unshift account_id
|
|
||||||
@offers.push sliced
|
|
||||||
# @offers[account_id] = obj.offers
|
|
||||||
|
|
||||||
base_reserve: ->
|
|
||||||
@declaration.reserve?.base ? "50.0"
|
|
||||||
|
|
||||||
incr_reserve: ->
|
|
||||||
@declaration.reserve?.base ? "12.5"
|
|
||||||
|
|
||||||
check_reserves: ->
|
|
||||||
base_reserve_amt = @base_reserve()
|
|
||||||
incr_reserve_amt = @incr_reserve()
|
|
||||||
|
|
||||||
base_reserve = @parse_amount base_reserve_amt
|
|
||||||
inc_reserve = @parse_amount incr_reserve_amt
|
|
||||||
|
|
||||||
@assert base_reserve != null,
|
|
||||||
"Base reserve amount #{base_reserve_amt} is invalid"
|
|
||||||
|
|
||||||
@assert base_reserve != null,
|
|
||||||
"incremental amount #{incr_reserve_amt} is invalid"
|
|
||||||
|
|
||||||
for account_id, account of @declaration.accounts
|
|
||||||
total_needed = base_reserve.clone()
|
|
||||||
owner_count = 0
|
|
||||||
|
|
||||||
a_offers = @offers_by_ci[account_id]
|
|
||||||
if a_offers?
|
|
||||||
if a_offers.xrp_total?
|
|
||||||
total_needed = total_needed.add a_offers.xrp_total
|
|
||||||
if a_offers.offers?
|
|
||||||
owner_count += @offers_by_ci[account_id].offers.length
|
|
||||||
|
|
||||||
if @trusts_by_ci[account_id]?
|
|
||||||
owner_count += Object.keys(@trusts_by_ci[account_id]).length
|
|
||||||
|
|
||||||
owner_count_amount = Amount.from_json(String(owner_count))
|
|
||||||
inc_reserve_n = owner_count_amount.multiply(inc_reserve)
|
|
||||||
total_needed = total_needed.add(inc_reserve_n)
|
|
||||||
|
|
||||||
@assert @accounts[account_id].compareTo total_needed != - 1,
|
|
||||||
"Account #{account_id} needs more XRP for reserve"
|
|
||||||
|
|
||||||
@reserves[account_id] = total_needed
|
|
||||||
|
|
||||||
format_payments: ->
|
|
||||||
# We do these first as the following @ious need xrp to issue ious ;0
|
|
||||||
for account_id, xrps of @accounts
|
|
||||||
@xrp_payments.push ['root', account_id, xrps]
|
|
||||||
|
|
||||||
for account_id, ious of @ious
|
|
||||||
for curr_issuer, amt of ious
|
|
||||||
src = @realias_issuer amt.issuer().to_json()
|
|
||||||
dst = account_id
|
|
||||||
@iou_payments.push [src, dst, amt]
|
|
||||||
|
|
||||||
format_trusts: ->
|
|
||||||
for account_id, trusts of @trusts_by_ci
|
|
||||||
for curr_issuer, amt of trusts
|
|
||||||
@trusts.push [account_id, amt]
|
|
||||||
|
|
||||||
transactor: (fn, args_list, on_each, callback) ->
|
|
||||||
if args_list.length == 0
|
|
||||||
return callback()
|
|
||||||
|
|
||||||
if not callback?
|
|
||||||
callback = on_each
|
|
||||||
on_each = null
|
|
||||||
|
|
||||||
@assert callback?, "Must supply a callback"
|
|
||||||
finalized = {
|
|
||||||
n: args_list.length
|
|
||||||
one: ->
|
|
||||||
if --finalized.n <= 0
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
|
|
||||||
async.concatSeries(args_list, ((args, callback) =>
|
|
||||||
tx = @remote.transaction()
|
|
||||||
on_each?(args..., tx)
|
|
||||||
fn.apply(tx, args).on("proposed", (m) =>
|
|
||||||
@assert m.engine_result is "tesSUCCESS", "Transactor failure: #{pretty_json m}"
|
|
||||||
callback()
|
|
||||||
).on('final', (m) =>
|
|
||||||
finalized.one()
|
|
||||||
)
|
|
||||||
.on("error", (m) =>
|
|
||||||
assert false, pretty_json m
|
|
||||||
).submit()
|
|
||||||
),
|
|
||||||
=> testutils.ledger_close @remote, ->
|
|
||||||
)
|
|
||||||
|
|
||||||
requester: (fn, args_list, on_each, callback) ->
|
|
||||||
if not callback?
|
|
||||||
callback = on_each
|
|
||||||
on_each = null
|
|
||||||
|
|
||||||
@assert callback?, "Must supply a callback"
|
|
||||||
|
|
||||||
async.concatSeries(args_list, ((args, callback) =>
|
|
||||||
req = fn.apply @remote, args
|
|
||||||
on_each?(args..., req)
|
|
||||||
req.on("success", (m) =>
|
|
||||||
if m.status?
|
|
||||||
@assert m.status is "success", "requester failure: #{pretty_json m}"
|
|
||||||
callback()
|
|
||||||
).on("error", (m) =>
|
|
||||||
@assert false, pretty_json m
|
|
||||||
).request()
|
|
||||||
), -> callback())
|
|
||||||
|
|
||||||
ensure_config_has_test_accounts: ->
|
|
||||||
for account of @declaration.accounts
|
|
||||||
if not @config.accounts[account]?
|
|
||||||
acc = @config.accounts[account] = {}
|
|
||||||
user = new TestAccount(account)
|
|
||||||
acc.account = user.address
|
|
||||||
acc.secret = user.passphrase
|
|
||||||
# Index by nickname ...
|
|
||||||
@remote.set_secret account, acc.secret
|
|
||||||
# ... and by account ID
|
|
||||||
@remote.set_secret acc.account, acc.secret
|
|
||||||
@setup_issuer_realiaser()
|
|
||||||
|
|
||||||
pretty_json: (v) ->
|
|
||||||
@realias_issuer pretty_json(v)
|
|
||||||
|
|
||||||
constructor: (declaration, @assert, @remote, @config) ->
|
|
||||||
@declaration = declaration
|
|
||||||
@accounts = {} # {$account_id : $xrp_amt}
|
|
||||||
@trusts_by_ci = {} # {$account_id : {$currency/$issuer : $iou_amt}}
|
|
||||||
@ious = {} # {$account_id : {$currency/$issuer : $iou_amt}}
|
|
||||||
@offers_by_ci = {} # {$account_id : {offers: [], $currency/$issuer : {total: $iou_amt}}}
|
|
||||||
@reserves = {}
|
|
||||||
|
|
||||||
@xrp_payments = [] # {$account_id: []}
|
|
||||||
@trusts = [] # {$account_id: []}
|
|
||||||
@iou_payments = [] # {$account_id: []}
|
|
||||||
@offers = [] # {$account_id: []}
|
|
||||||
|
|
||||||
@ensure_config_has_test_accounts()
|
|
||||||
@compile_accounts_balances_and_implicit_trusts()
|
|
||||||
@compile_explicit_trusts()
|
|
||||||
@compile_offers()
|
|
||||||
@check_reserves()
|
|
||||||
@format_payments()
|
|
||||||
@format_trusts()
|
|
||||||
|
|
||||||
setup: (log, done) ->
|
|
||||||
LOG = (m) ->
|
|
||||||
self.what = m
|
|
||||||
log(m)
|
|
||||||
|
|
||||||
accounts = (k for k,ac of @accounts).sort()
|
|
||||||
@remote.set_account_seq(seq, 1) for seq in accounts.concat 'root' # <--
|
|
||||||
accounts_apply_arguments = ([ac] for ac in @accounts)
|
|
||||||
self = this
|
|
||||||
|
|
||||||
async.waterfall [
|
|
||||||
(cb) ->
|
|
||||||
self.transactor(
|
|
||||||
Transaction::payment,
|
|
||||||
self.xrp_payments,
|
|
||||||
((src, dest, amt) ->
|
|
||||||
LOG("Account `#{src}` creating account `#{dest}` by
|
|
||||||
making payment of #{amt.to_text_full()}") ),
|
|
||||||
cb)
|
|
||||||
(cb) ->
|
|
||||||
self.transactor(
|
|
||||||
Transaction::ripple_line_set,
|
|
||||||
self.trusts,
|
|
||||||
((src, amt) ->
|
|
||||||
issuer = self.realias_issuer amt.issuer().to_json()
|
|
||||||
currency = amt.currency().to_json()
|
|
||||||
LOG("Account `#{src}` trusts account `#{issuer}` for
|
|
||||||
#{amt.to_text()} #{currency}") ),
|
|
||||||
cb)
|
|
||||||
(cb) ->
|
|
||||||
self.transactor(
|
|
||||||
Transaction::payment,
|
|
||||||
self.iou_payments,
|
|
||||||
((src, dest, amt, tx) ->
|
|
||||||
LOG("Account `#{src}` is making a payment of #{amt.to_text_full()}
|
|
||||||
to `#{dest}`") ),
|
|
||||||
cb)
|
|
||||||
(cb) ->
|
|
||||||
self.transactor(
|
|
||||||
Transaction::offer_create,
|
|
||||||
self.offers,
|
|
||||||
((src, pays, gets) ->
|
|
||||||
LOG("Account `#{src}` is selling #{gets.to_text_full()}
|
|
||||||
for #{pays.to_text_full()}")),
|
|
||||||
cb)
|
|
||||||
(cb) ->
|
|
||||||
testutils.ledger_close self.remote, cb
|
|
||||||
(cb) ->
|
|
||||||
self.requester(Remote::request_account_lines, accounts_apply_arguments,
|
|
||||||
((acc) ->
|
|
||||||
LOG("Checking account_lines for #{acc}")),
|
|
||||||
cb)
|
|
||||||
(cb) ->
|
|
||||||
self.requester(Remote::request_account_info, accounts_apply_arguments,
|
|
||||||
((acc) ->
|
|
||||||
LOG("Checking account_info for #{acc}")),
|
|
||||||
cb)
|
|
||||||
], (error) ->
|
|
||||||
assert !error,
|
|
||||||
"There was an error @ #{self.what}"
|
|
||||||
done()
|
|
||||||
@@ -1 +1 @@
|
|||||||
--reporter spec --compilers coffee:coffee-script --ui tdd --timeout 3000 --slow 600
|
--reporter spec --compilers coffee:coffee-script --ui tdd --timeout 10000 --slow 600
|
||||||
@@ -1,677 +0,0 @@
|
|||||||
################################### REQUIRES ###################################
|
|
||||||
|
|
||||||
extend = require 'extend'
|
|
||||||
fs = require 'fs'
|
|
||||||
async = require 'async'
|
|
||||||
deep_eq = require 'deep-equal'
|
|
||||||
|
|
||||||
{Amount
|
|
||||||
Remote
|
|
||||||
Seed
|
|
||||||
Base
|
|
||||||
Transaction
|
|
||||||
PathFind
|
|
||||||
sjcl
|
|
||||||
UInt160} = require 'ripple-lib'
|
|
||||||
|
|
||||||
testutils = require './testutils'
|
|
||||||
{Server} = require './server'
|
|
||||||
{LedgerState, TestAccount} = require './ledger-state'
|
|
||||||
{test_accounts} = require './random-test-addresses'
|
|
||||||
|
|
||||||
simple_assert = require 'assert'
|
|
||||||
|
|
||||||
#################################### README ####################################
|
|
||||||
"""
|
|
||||||
The tests are written in a declarative style:
|
|
||||||
|
|
||||||
Each case has an entry in the `path_finding_cases` object
|
|
||||||
The key translates to a `suite(key, {...})`
|
|
||||||
The `{...}` passed in is compiled into a setup/teardown for the `ledger` and
|
|
||||||
into a bunch of `test` invokations for the `paths_expected`
|
|
||||||
|
|
||||||
- aliases are used throughout for easier reading
|
|
||||||
|
|
||||||
- test account addresses will be created `on the fly`
|
|
||||||
|
|
||||||
no need to declare in testconfig.js
|
|
||||||
debugged responses from the server substitute addresses for aliases
|
|
||||||
|
|
||||||
- The fixtures are setup just once for each ledger, multiple path finding
|
|
||||||
tests can be executed
|
|
||||||
|
|
||||||
- `paths_expected` top level keys are group names
|
|
||||||
2nd level keys are path test declarations
|
|
||||||
|
|
||||||
test declaration keys can be suffixed meaningfully with
|
|
||||||
|
|
||||||
`_skip`
|
|
||||||
`_only`
|
|
||||||
|
|
||||||
test declaration values can set
|
|
||||||
|
|
||||||
debug: true
|
|
||||||
|
|
||||||
Will dump the path declaration and
|
|
||||||
translated request and subsequent response
|
|
||||||
|
|
||||||
- hops in `alternatives[*][paths][*]` can be written in shorthand
|
|
||||||
eg.
|
|
||||||
ABC/G3|G3
|
|
||||||
get `ABC/G3` through `G3`
|
|
||||||
|
|
||||||
ABC/M1|M1
|
|
||||||
get `ABC/M1` through `M1`
|
|
||||||
|
|
||||||
XRP|$
|
|
||||||
get `XRP` through `$`
|
|
||||||
$ signifies an order book rather than account
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Tests can be written in the 'path-tests.json' file in same directory # <--
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
"""
|
|
||||||
#################################### HELPERS ###################################
|
|
||||||
|
|
||||||
assert = simple_assert
|
|
||||||
refute = (cond, msg) -> assert(!cond, msg)
|
|
||||||
prettyj = pretty_json = (v) -> JSON.stringify(v, undefined, 2)
|
|
||||||
|
|
||||||
propagater = (done) ->
|
|
||||||
(f) ->
|
|
||||||
->
|
|
||||||
return if done.aborted
|
|
||||||
try
|
|
||||||
f(arguments...)
|
|
||||||
catch e
|
|
||||||
done.aborted = true
|
|
||||||
throw e
|
|
||||||
|
|
||||||
assert_match = (o, key_vals, message) ->
|
|
||||||
"""
|
|
||||||
assert_match path[i], matcher,
|
|
||||||
"alternative[#{ai}].paths[#{pi}]"
|
|
||||||
"""
|
|
||||||
|
|
||||||
for k,v of key_vals
|
|
||||||
assert.equal o[k], v, message
|
|
||||||
|
|
||||||
#################################### CONFIG ####################################
|
|
||||||
|
|
||||||
config = testutils.init_config()
|
|
||||||
|
|
||||||
############################### ALTERNATIVES TEST ##############################
|
|
||||||
|
|
||||||
expand_alternative = (alt) ->
|
|
||||||
"""
|
|
||||||
|
|
||||||
Make explicit the currency and issuer in each hop in paths_computed
|
|
||||||
|
|
||||||
"""
|
|
||||||
amt = Amount.from_json(alt.source_amount)
|
|
||||||
|
|
||||||
for path in alt.paths_computed
|
|
||||||
prev_issuer = amt.issuer().to_json()
|
|
||||||
prev_currency = amt.currency().to_json()
|
|
||||||
|
|
||||||
for hop, hop_i in path
|
|
||||||
if not hop.currency?
|
|
||||||
hop.currency = prev_currency
|
|
||||||
|
|
||||||
if not hop.issuer? and hop.currency != 'XRP'
|
|
||||||
if hop.account?
|
|
||||||
hop.issuer = hop.account
|
|
||||||
else
|
|
||||||
hop.issuer = prev_issuer
|
|
||||||
|
|
||||||
if hop.type & 0x10
|
|
||||||
prev_currency = hop.currency
|
|
||||||
|
|
||||||
if hop.type & 0x20
|
|
||||||
prev_issuer = hop.issuer
|
|
||||||
else if hop.account?
|
|
||||||
prev_issuer = hop.account
|
|
||||||
|
|
||||||
return alt
|
|
||||||
|
|
||||||
create_shorthand = (alternatives) ->
|
|
||||||
"""
|
|
||||||
|
|
||||||
Convert explicit paths_computed into the format used by `paths_expected`
|
|
||||||
These can be pasted in as the basis of tests.
|
|
||||||
|
|
||||||
"""
|
|
||||||
shorthand = []
|
|
||||||
|
|
||||||
for alt in alternatives
|
|
||||||
short_alt = {}
|
|
||||||
shorthand.push short_alt
|
|
||||||
|
|
||||||
amt = Amount.from_json alt.source_amount
|
|
||||||
if amt.is_native()
|
|
||||||
short_alt.amount = amt.to_human()
|
|
||||||
if not (~short_alt.amount.search('.'))
|
|
||||||
short_alt.amount = short_alt.amount + '.0'
|
|
||||||
else
|
|
||||||
short_alt.amount = amt.to_text_full()
|
|
||||||
|
|
||||||
short_alt.paths = []
|
|
||||||
|
|
||||||
for path in alt.paths_computed
|
|
||||||
short_path = []
|
|
||||||
short_alt.paths.push short_path
|
|
||||||
|
|
||||||
for node in path
|
|
||||||
hop = node.currency
|
|
||||||
hop = "#{hop}/#{node.issuer}" if node.issuer?
|
|
||||||
hop = "#{hop}|#{if node.account? then node.account else "$"}"
|
|
||||||
short_path.push hop
|
|
||||||
|
|
||||||
return shorthand
|
|
||||||
|
|
||||||
ensure_list = (v) ->
|
|
||||||
if Array.isArray(v)
|
|
||||||
v
|
|
||||||
else
|
|
||||||
[v]
|
|
||||||
|
|
||||||
test_alternatives_factory = (realias_pp, realias_text) ->
|
|
||||||
"""
|
|
||||||
|
|
||||||
We are using a factory to create `test_alternatives` because it needs the
|
|
||||||
per ledger `realias_*` functions
|
|
||||||
|
|
||||||
"""
|
|
||||||
hop_matcher = (decl_hop) ->
|
|
||||||
[ci, f] = decl_hop.split('|')
|
|
||||||
if not f?
|
|
||||||
throw new Error("No `|` in #{decl_hop}")
|
|
||||||
|
|
||||||
[c, i] = ci.split('/')
|
|
||||||
is_account = if f == '$' then false else true
|
|
||||||
matcher = currency: c
|
|
||||||
matcher.issuer = i if i?
|
|
||||||
matcher.account = f if is_account
|
|
||||||
matcher
|
|
||||||
|
|
||||||
match_path = (test, path, ai, pi) ->
|
|
||||||
test = (hop_matcher(hop) for hop in test)
|
|
||||||
assert.equal path.length, test.length,
|
|
||||||
"alternative[#{ai}] path[#{pi}] expecting #{test.length} hops"
|
|
||||||
|
|
||||||
for matcher, i in test
|
|
||||||
assert_match path[i], matcher,
|
|
||||||
"alternative[#{ai}].paths[#{pi}]"
|
|
||||||
return
|
|
||||||
|
|
||||||
simple_match_path = (test, path, ai, pi) ->
|
|
||||||
"""
|
|
||||||
|
|
||||||
Params
|
|
||||||
@test
|
|
||||||
|
|
||||||
A shorthand specified path
|
|
||||||
|
|
||||||
@path
|
|
||||||
|
|
||||||
A path as returned by the server with `expand_alternative` done
|
|
||||||
so issuer and currency are always stated.
|
|
||||||
|
|
||||||
"""
|
|
||||||
test = (hop_matcher(hop) for hop in test)
|
|
||||||
return false if not test.length == path.length
|
|
||||||
|
|
||||||
for matcher, i in test
|
|
||||||
for k, v of matcher
|
|
||||||
return false if not path[i]?
|
|
||||||
if path[i][k] != v
|
|
||||||
return false
|
|
||||||
true
|
|
||||||
|
|
||||||
amounts = ->
|
|
||||||
(Amount.from_json a for a in arguments)
|
|
||||||
|
|
||||||
amounts_text = ->
|
|
||||||
(realias_text a.to_text_full() for a in arguments)
|
|
||||||
|
|
||||||
check_for_no_redundant_paths = (alternatives) ->
|
|
||||||
for alt, i in alternatives
|
|
||||||
existing_paths = []
|
|
||||||
for path in alt.paths_computed
|
|
||||||
for existing in existing_paths
|
|
||||||
assert !(deep_eq path, existing),
|
|
||||||
"Duplicate path in alternatives[#{i}]\n"+
|
|
||||||
"#{realias_pp alternatives[0]}"
|
|
||||||
|
|
||||||
existing_paths.push path
|
|
||||||
return
|
|
||||||
|
|
||||||
test_alternatives = (test, actual, error_context) ->
|
|
||||||
"""
|
|
||||||
|
|
||||||
Params:
|
|
||||||
@test
|
|
||||||
alternatives in shorthand format
|
|
||||||
|
|
||||||
@actual
|
|
||||||
alternatives as returned in a `path_find` response
|
|
||||||
|
|
||||||
@error_context
|
|
||||||
|
|
||||||
a function providing a string with extra context to provide to assertion
|
|
||||||
messages
|
|
||||||
|
|
||||||
"""
|
|
||||||
check_for_no_redundant_paths actual
|
|
||||||
|
|
||||||
for t, ti in ensure_list(test)
|
|
||||||
a = actual[ti]
|
|
||||||
[t_amt, a_amt] = amounts(t.amount, a.source_amount)
|
|
||||||
[t_amt_txt, a_amt_txt] = amounts_text(t_amt, a_amt)
|
|
||||||
|
|
||||||
# console.log typeof t_amt
|
|
||||||
|
|
||||||
assert t_amt.equals(a_amt),
|
|
||||||
"Expecting alternative[#{ti}].amount: "+
|
|
||||||
"#{t_amt_txt} == #{a_amt_txt}"
|
|
||||||
|
|
||||||
t_paths = ensure_list(t.paths)
|
|
||||||
|
|
||||||
tn = t_paths.length
|
|
||||||
an = a.paths_computed.length
|
|
||||||
assert.equal tn, an, "Different number of paths specified for alternative[#{ti}]"+
|
|
||||||
", expected: #{prettyj t_paths}, "+
|
|
||||||
"actual(shorthand): #{prettyj create_shorthand actual}"+
|
|
||||||
"actual(verbose): #{prettyj a.paths_computed}"+
|
|
||||||
error_context()
|
|
||||||
|
|
||||||
for p, i in t_paths
|
|
||||||
matched = false
|
|
||||||
|
|
||||||
for m in a.paths_computed
|
|
||||||
if simple_match_path(p, m, ti, i)
|
|
||||||
matched = true
|
|
||||||
break
|
|
||||||
|
|
||||||
assert matched, "Can't find a match for path[#{i}]: #{prettyj p} "+
|
|
||||||
"amongst #{prettyj create_shorthand [a]}"+
|
|
||||||
error_context()
|
|
||||||
return
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
create_path_test = (pth) ->
|
|
||||||
return (done) ->
|
|
||||||
propagates = propagater done
|
|
||||||
|
|
||||||
self = this
|
|
||||||
WHAT = self.log_what
|
|
||||||
ledger = self.ledger
|
|
||||||
test_alternatives = test_alternatives_factory ledger.pretty_json.bind(ledger),
|
|
||||||
ledger.realias_issuer
|
|
||||||
|
|
||||||
|
|
||||||
WHAT "#{pth.title}: #{pth.src} sending #{pth.dst}, "+
|
|
||||||
"#{pth.send}, via #{pth.via}"
|
|
||||||
|
|
||||||
one_message = (f) ->
|
|
||||||
self.remote._servers[0].once 'before_send_message_for_non_mutators', f
|
|
||||||
|
|
||||||
sent = "TODO: need to patch ripple-lib"
|
|
||||||
one_message (m) -> sent = m
|
|
||||||
|
|
||||||
error_info = (m, more) ->
|
|
||||||
info = path_expected: pth, path_find_request: sent, path_find_updates: m
|
|
||||||
extend(info, more) if more?
|
|
||||||
ledger.pretty_json(info)
|
|
||||||
|
|
||||||
assert Amount.from_json(pth.send).is_valid(),
|
|
||||||
"#{pth.send} is not valid Amount"
|
|
||||||
|
|
||||||
_src = UInt160.json_rewrite(pth.src)
|
|
||||||
_dst = UInt160.json_rewrite(pth.dst)
|
|
||||||
_amt = Amount.from_json(pth.send)
|
|
||||||
|
|
||||||
# self.server.clear_logs() "TODO: need to patch ripple-lib"
|
|
||||||
pf = self.remote.path_find(_src, _dst, _amt, [{currency: pth.via}])
|
|
||||||
|
|
||||||
updates = 0
|
|
||||||
max_seen = 0
|
|
||||||
messages = {}
|
|
||||||
|
|
||||||
pf.on "error", propagates (m) -> # <--
|
|
||||||
assert false, "fail (error): #{error_info(m)}"
|
|
||||||
done()
|
|
||||||
|
|
||||||
pf.on "update", propagates (m) -> # <--
|
|
||||||
# TODO:hack:
|
|
||||||
expand_alternative alt for alt in m.alternatives
|
|
||||||
|
|
||||||
messages[if updates then "update-#{updates}" else 'initial-response'] = m
|
|
||||||
updates++
|
|
||||||
|
|
||||||
assert m.alternatives.length >= max_seen,
|
|
||||||
"Subsequent path_find update' should never have less " +
|
|
||||||
"alternatives:\n#{ledger.pretty_json messages}"
|
|
||||||
|
|
||||||
max_seen = m.alternatives.length
|
|
||||||
|
|
||||||
if updates == 2
|
|
||||||
testutils.ledger_close(self.remote, -> )
|
|
||||||
|
|
||||||
if updates == 3
|
|
||||||
# "TODO: need to patch ripple-lib"
|
|
||||||
# self.log_pre(self.server.get_logs(), "Server Logs")
|
|
||||||
|
|
||||||
if pth.do_send?
|
|
||||||
do_send( (ledger.pretty_json.bind ledger), WHAT, self.remote, pth,
|
|
||||||
messages['update-2'], done )
|
|
||||||
|
|
||||||
if pth.debug
|
|
||||||
console.log ledger.pretty_json(messages)
|
|
||||||
console.log error_info(m)
|
|
||||||
console.log ledger.pretty_json create_shorthand(m.alternatives)
|
|
||||||
|
|
||||||
if pth.alternatives?
|
|
||||||
# We realias before doing any comparisons
|
|
||||||
alts = ledger.realias_issuer(JSON.stringify(m.alternatives))
|
|
||||||
alts = JSON.parse(alts)
|
|
||||||
test = pth.alternatives
|
|
||||||
|
|
||||||
assert test.length == alts.length,
|
|
||||||
"Number of `alternatives` specified is different: "+
|
|
||||||
"#{error_info(m)}"
|
|
||||||
|
|
||||||
if test.length == alts.length
|
|
||||||
test_alternatives(pth.alternatives, alts, -> error_info(m))
|
|
||||||
|
|
||||||
if pth.n_alternatives?
|
|
||||||
assert pth.n_alternatives == m.alternatives.length,
|
|
||||||
"fail (wrong n_alternatives): #{error_info(m)}"
|
|
||||||
|
|
||||||
done() if not pth.do_send?
|
|
||||||
|
|
||||||
################################ SUITE CREATION ################################
|
|
||||||
|
|
||||||
skip_or_only = (title, test_or_suite) ->
|
|
||||||
endsWith = (s, suffix) ->
|
|
||||||
~s.indexOf(suffix, s.length - suffix.length)
|
|
||||||
|
|
||||||
if endsWith title, '_only'
|
|
||||||
test_or_suite.only
|
|
||||||
else if endsWith title, '_skip'
|
|
||||||
test_or_suite.skip
|
|
||||||
else
|
|
||||||
test_or_suite
|
|
||||||
|
|
||||||
gather_path_definers = (path_expected) ->
|
|
||||||
tests = []
|
|
||||||
|
|
||||||
for group, subgroup of path_expected
|
|
||||||
for title, path of subgroup
|
|
||||||
definer_factory = (group, title, path) ->
|
|
||||||
path.title = "#{[group, title].join('.')}"
|
|
||||||
test_func = skip_or_only path.title, test
|
|
||||||
->
|
|
||||||
test_func(path.title, create_path_test(path) )
|
|
||||||
|
|
||||||
tests.push definer_factory(group, title, path)
|
|
||||||
tests
|
|
||||||
|
|
||||||
suite_factory = (declaration) ->
|
|
||||||
->
|
|
||||||
context = null
|
|
||||||
|
|
||||||
suiteSetup (done) ->
|
|
||||||
context = @
|
|
||||||
@log_what = ->
|
|
||||||
|
|
||||||
@uniquely_gifted = 'yes'
|
|
||||||
|
|
||||||
testutils.build_setup().call @, ->
|
|
||||||
context.ledger = new LedgerState(declaration.ledger,
|
|
||||||
assert,
|
|
||||||
context.remote,
|
|
||||||
config)
|
|
||||||
|
|
||||||
context.ledger.setup(context.log_what, done)
|
|
||||||
|
|
||||||
suiteTeardown (done) ->
|
|
||||||
testutils.build_teardown().call context, done
|
|
||||||
|
|
||||||
for definer in gather_path_definers(declaration.paths_expected)
|
|
||||||
definer()
|
|
||||||
|
|
||||||
define_suites = (path_finding_cases) ->
|
|
||||||
for case_name, declaration of path_finding_cases
|
|
||||||
suite_func = skip_or_only case_name, suite
|
|
||||||
suite_func case_name, suite_factory(declaration)
|
|
||||||
|
|
||||||
############################## PATH FINDING CASES ##############################
|
|
||||||
# Later we reference A0, the `unknown account`, directly embedding the full
|
|
||||||
# address.
|
|
||||||
A0 = (new TestAccount('A0')).address
|
|
||||||
assert A0 == 'rBmhuVAvi372AerwzwERGjhLjqkMmAwxX'
|
|
||||||
|
|
||||||
path_finding_cases_string = fs.readFileSync(__dirname + "/path-tests.json")
|
|
||||||
path_finding_cases = JSON.parse path_finding_cases_string
|
|
||||||
|
|
||||||
# You need two gateways, same currency. A market maker. A source that trusts one
|
|
||||||
# gateway and holds its currency, and a destination that trusts the other.
|
|
||||||
|
|
||||||
extend path_finding_cases,
|
|
||||||
"Path Tests (Bitstamp + SnapSwap account holders | liquidity provider with no offers)":
|
|
||||||
ledger:
|
|
||||||
accounts:
|
|
||||||
G1BS:
|
|
||||||
balance: ["1000.0"]
|
|
||||||
G2SW:
|
|
||||||
balance: ["1000.0"]
|
|
||||||
A1:
|
|
||||||
balance: ["1000.0", "1000/HKD/G1BS"]
|
|
||||||
trusts: ["2000/HKD/G1BS"]
|
|
||||||
A2:
|
|
||||||
balance: ["1000.0", "1000/HKD/G2SW"]
|
|
||||||
trusts: ["2000/HKD/G2SW"]
|
|
||||||
M1:
|
|
||||||
# SnapSwap wants to be able to set trust line quality settings so they
|
|
||||||
# can charge a fee when transactions ripple across. Liquitidy
|
|
||||||
# provider, via trusting/holding both accounts
|
|
||||||
balance: ["11000.0",
|
|
||||||
"1200/HKD/G1BS",
|
|
||||||
"5000/HKD/G2SW"
|
|
||||||
]
|
|
||||||
trusts: ["100000/HKD/G1BS", "100000/HKD/G2SW"]
|
|
||||||
# We haven't got ANY offers
|
|
||||||
|
|
||||||
paths_expected: {
|
|
||||||
BS:
|
|
||||||
P1:
|
|
||||||
debug: false
|
|
||||||
src: "A1", dst: "A2", send: "10/HKD/A2", via: "HKD"
|
|
||||||
n_alternatives: 1
|
|
||||||
P2:
|
|
||||||
debug: false
|
|
||||||
src: "A2", dst: "A1", send: "10/HKD/A1", via: "HKD"
|
|
||||||
n_alternatives: 1
|
|
||||||
P3:
|
|
||||||
debug: false
|
|
||||||
src: "G1BS", dst: "A2", send: "10/HKD/A2", via: "HKD"
|
|
||||||
alternatives: [
|
|
||||||
amount: "10/HKD/G1BS",
|
|
||||||
paths: [["HKD/M1|M1", "HKD/G2SW|G2SW"]]
|
|
||||||
]
|
|
||||||
P5:
|
|
||||||
debug: false
|
|
||||||
src: "M1",
|
|
||||||
send: "10/HKD/M1",
|
|
||||||
dst: "G1BS",
|
|
||||||
via: "HKD"
|
|
||||||
P4:
|
|
||||||
debug: false
|
|
||||||
src: "G2SW", send: "10/HKD/A1", dst: "A1", via: "HKD"
|
|
||||||
alternatives: [
|
|
||||||
amount: "10/HKD/G2SW",
|
|
||||||
paths: [["HKD/M1|M1", "HKD/G1BS|G1BS"]]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"Path Tests #4 (non-XRP to non-XRP, same currency)": {
|
|
||||||
ledger:
|
|
||||||
accounts:
|
|
||||||
G1: balance: ["1000.0"]
|
|
||||||
G2: balance: ["1000.0"]
|
|
||||||
G3: balance: ["1000.0"]
|
|
||||||
G4: balance: ["1000.0"]
|
|
||||||
A1:
|
|
||||||
balance: ["1000.0", "1000/HKD/G1"]
|
|
||||||
trusts: ["2000/HKD/G1"]
|
|
||||||
A2:
|
|
||||||
balance: ["1000.0", "1000/HKD/G2"]
|
|
||||||
trusts: ["2000/HKD/G2"]
|
|
||||||
A3:
|
|
||||||
balance: ["1000.0", "1000/HKD/G1"]
|
|
||||||
trusts: ["2000/HKD/G1"]
|
|
||||||
A4:
|
|
||||||
balance: ["10000.0"]
|
|
||||||
M1:
|
|
||||||
balance: ["11000.0", "1200/HKD/G1", "5000/HKD/G2"]
|
|
||||||
trusts: ["100000/HKD/G1", "100000/HKD/G2"]
|
|
||||||
offers: [
|
|
||||||
["1000/HKD/G1", "1000/HKD/G2"]
|
|
||||||
]
|
|
||||||
M2:
|
|
||||||
balance: ["11000.0", "1200/HKD/G1", "5000/HKD/G2"]
|
|
||||||
trusts: ["100000/HKD/G1", "100000/HKD/G2"]
|
|
||||||
offers: [
|
|
||||||
["10000.0", "1000/HKD/G2"]
|
|
||||||
["1000/HKD/G1", "10000.0"]
|
|
||||||
]
|
|
||||||
|
|
||||||
paths_expected: {
|
|
||||||
T4:
|
|
||||||
"A) Borrow or repay":
|
|
||||||
comment: 'Source -> Destination (repay source issuer)'
|
|
||||||
src: "A1", send: "10/HKD/G1", dst: "G1", via: "HKD"
|
|
||||||
alternatives: [amount: "10/HKD/A1", paths: []]
|
|
||||||
|
|
||||||
"A2) Borrow or repay":
|
|
||||||
comment: 'Source -> Destination (repay destination issuer)'
|
|
||||||
src: "A1", send: "10/HKD/A1", dst: "G1", via: "HKD"
|
|
||||||
alternatives: [amount: "10/HKD/A1", paths: []]
|
|
||||||
|
|
||||||
"B) Common gateway":
|
|
||||||
comment: 'Source -> AC -> Destination'
|
|
||||||
src: "A1", send: "10/HKD/A3", dst: "A3", via: "HKD"
|
|
||||||
alternatives: [amount: "10/HKD/A1", paths: [["HKD/G1|G1"]]]
|
|
||||||
|
|
||||||
"C) Gateway to gateway":
|
|
||||||
comment: 'Source -> OB -> Destination'
|
|
||||||
src: "G1", send: "10/HKD/G2", dst: "G2", via: "HKD"
|
|
||||||
debug: false
|
|
||||||
alternatives: [
|
|
||||||
amount: "10/HKD/G1"
|
|
||||||
paths: [["HKD/M2|M2"],
|
|
||||||
["HKD/M1|M1"],
|
|
||||||
["HKD/G2|$"]
|
|
||||||
["XRP|$", "HKD/G2|$"]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
"D) User to unlinked gateway via order book":
|
|
||||||
comment: 'Source -> AC -> OB -> Destination'
|
|
||||||
src: "A1", send: "10/HKD/G2", dst: "G2", via: "HKD"
|
|
||||||
debug: false
|
|
||||||
alternatives: [
|
|
||||||
amount: "10/HKD/A1"
|
|
||||||
paths: [
|
|
||||||
["HKD/G1|G1", "HKD/G2|$"], # <--
|
|
||||||
["HKD/G1|G1", "HKD/M2|M2"],
|
|
||||||
["HKD/G1|G1", "HKD/M1|M1"],
|
|
||||||
["HKD/G1|G1", "XRP|$", "HKD/G2|$"]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
"I4) XRP bridge":
|
|
||||||
comment: 'Source -> AC -> OB to XRP -> OB from XRP -> AC -> Destination'
|
|
||||||
src: "A1", send: "10/HKD/A2", dst: "A2", via: "HKD"
|
|
||||||
debug: false
|
|
||||||
alternatives: [
|
|
||||||
amount: "10/HKD/A1",
|
|
||||||
paths: [
|
|
||||||
# Focus
|
|
||||||
["HKD/G1|G1", "HKD/G2|$", "HKD/G2|G2" ],
|
|
||||||
["HKD/G1|G1", "XRP|$", "HKD/G2|$", "HKD/G2|G2"], # <--
|
|
||||||
# Incidental
|
|
||||||
["HKD/G1|G1", "HKD/M1|M1", "HKD/G2|G2"],
|
|
||||||
["HKD/G1|G1", "HKD/M2|M2", "HKD/G2|G2"]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Path Tests #2 (non-XRP to non-XRP, same currency)": {
|
|
||||||
ledger:
|
|
||||||
accounts:
|
|
||||||
G1: balance: ["1000.0"]
|
|
||||||
G2: balance: ["1000.0"]
|
|
||||||
A1:
|
|
||||||
balance: ["1000.0", "1000/HKD/G1"]
|
|
||||||
trusts: ["2000/HKD/G1"]
|
|
||||||
A2:
|
|
||||||
balance: ["1000.0", "1000/HKD/G2"]
|
|
||||||
trusts: ["2000/HKD/G2"]
|
|
||||||
A3:
|
|
||||||
balance: ["1000.0"]
|
|
||||||
trusts: ["2000/HKD/A2"]
|
|
||||||
M1:
|
|
||||||
balance: ["11000.0", "5000/HKD/G1", "5000/HKD/G2"]
|
|
||||||
trusts: ["100000/HKD/G1", "100000/HKD/G2"]
|
|
||||||
offers: [
|
|
||||||
["1000/HKD/G1", "1000/HKD/G2"]
|
|
||||||
# ["2000/HKD/G2", "2000/HKD/G1"]
|
|
||||||
# ["2000/HKD/M1", "2000/HKD/G1"]
|
|
||||||
# ["100.0", "1000/HKD/G1"]
|
|
||||||
# ["1000/HKD/G1", "100.0"]
|
|
||||||
]
|
|
||||||
|
|
||||||
paths_expected: {
|
|
||||||
T4:
|
|
||||||
"E) Gateway to user":
|
|
||||||
ledger: false
|
|
||||||
comment: 'Source -> OB -> AC -> Destination'
|
|
||||||
# comment: 'Gateway -> OB -> Gateway 2 -> User'
|
|
||||||
src: "G1", send: "10/HKD/A2", dst: "A2", via: "HKD"
|
|
||||||
debug: false
|
|
||||||
alternatives: [
|
|
||||||
amount: "10/HKD/G1"
|
|
||||||
paths: [
|
|
||||||
["HKD/G2|$", "HKD/G2|G2"],
|
|
||||||
["HKD/M1|M1", "HKD/G2|G2"]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
"F) Different gateways, ripple _skip":
|
|
||||||
comment: 'Source -> AC -> AC -> Destination'
|
|
||||||
|
|
||||||
"G) Different users of different gateways, ripple _skip":
|
|
||||||
comment: 'Source -> AC -> AC -> AC -> Destination'
|
|
||||||
|
|
||||||
"H) Different gateways, order book _skip":
|
|
||||||
comment: 'Source -> AC -> OB -> AC -> Destination'
|
|
||||||
|
|
||||||
"I1) XRP bridge _skip":
|
|
||||||
comment: 'Source -> OB to XRP -> OB from XRP -> Destination'
|
|
||||||
src: "A4", send: "10/HKD/G2", dst: "G2", via: "XRP"
|
|
||||||
debug: true
|
|
||||||
|
|
||||||
"I2) XRP bridge _skip":
|
|
||||||
comment: 'Source -> AC -> OB to XRP -> OB from XRP -> Destination'
|
|
||||||
|
|
||||||
"I3) XRP bridge _skip":
|
|
||||||
comment: 'Source -> OB to XRP -> OB from XRP -> AC -> Destination'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
################################# DEFINE SUITES ################################
|
|
||||||
|
|
||||||
define_suites(path_finding_cases)
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
{
|
|
||||||
"Path Tests #1 (XRP -> XRP) and #2 (XRP -> IOU)": {
|
|
||||||
|
|
||||||
"ledger": {"accounts": {"A1": {"balance": ["100000.0",
|
|
||||||
"3500/XYZ/G1",
|
|
||||||
"1200/ABC/G3"],
|
|
||||||
"trusts": ["5000/XYZ/G1",
|
|
||||||
"5000/ABC/G3"]},
|
|
||||||
"A2": {"balance": ["10000.0"],
|
|
||||||
"trusts": ["5000/XYZ/G2",
|
|
||||||
"5000/ABC/G3"]},
|
|
||||||
"A3": {"balance": ["1000.0"],
|
|
||||||
"trusts": ["1000/ABC/A2"]},
|
|
||||||
"G1": {"balance": ["1000.0"]},
|
|
||||||
"G2": {"balance": ["1000.0"]},
|
|
||||||
"G3": {"balance": ["1000.0"]},
|
|
||||||
"M1": {"balance": ["1000.0",
|
|
||||||
"25000/XYZ/G2",
|
|
||||||
"25000/ABC/G3"],
|
|
||||||
"offers": [["1000/XYZ/G1",
|
|
||||||
"1000/XYZ/G2"],
|
|
||||||
["10000.0",
|
|
||||||
"1000/ABC/G3"]],
|
|
||||||
"trusts": ["100000/XYZ/G1",
|
|
||||||
"100000/ABC/G3",
|
|
||||||
"100000/XYZ/G2"]}}},
|
|
||||||
|
|
||||||
"paths_expected": {"T1": {"A1": {"n_alternatives": 0,
|
|
||||||
"src": "A1",
|
|
||||||
"send": "10.0",
|
|
||||||
"dst": "A2",
|
|
||||||
"via": "XRP"},
|
|
||||||
"A2": {"comment": "Send to non existing account",
|
|
||||||
"src": "A1",
|
|
||||||
"send_comment": "malformed error not great for 10.0 amount",
|
|
||||||
"send": "200.0",
|
|
||||||
"dst": "rBmhuVAvi372AerwzwERGjhLjqkMmAwxX",
|
|
||||||
"via": "XRP",
|
|
||||||
"n_alternatives": 0}},
|
|
||||||
"T2": {"A": {"alternatives": [{"amount": "100.0",
|
|
||||||
"paths": [
|
|
||||||
["ABC/G3|$"]
|
|
||||||
]}],
|
|
||||||
"src": "A2",
|
|
||||||
"send": "10/ABC/G3",
|
|
||||||
"dst": "G3",
|
|
||||||
"via": "XRP",
|
|
||||||
"debug": 0,
|
|
||||||
"n_alternatives": 1},
|
|
||||||
"B": {"alternatives": [{"amount": "10.0",
|
|
||||||
"paths": [["ABC/G3|$",
|
|
||||||
"ABC/G3|G3"]]}],
|
|
||||||
"src": "A1",
|
|
||||||
"send": "1/ABC/A2",
|
|
||||||
"dst": "A2",
|
|
||||||
"via": "XRP",
|
|
||||||
"n_alternatives": 1},
|
|
||||||
"C": {"alternatives": [{"amount": "10.0",
|
|
||||||
"paths": [["ABC/G3|$",
|
|
||||||
"ABC/G3|G3",
|
|
||||||
"ABC/A2|A2"]]}],
|
|
||||||
"src": "A1",
|
|
||||||
"send": "1/ABC/A3",
|
|
||||||
"dst": "A3",
|
|
||||||
"via": "XRP",
|
|
||||||
"n_alternatives": 1}}}},
|
|
||||||
"Path Tests #3 (non-XRP to XRP)": {
|
|
||||||
|
|
||||||
"ledger": {"accounts": {"A1": {"balance": ["1000.0",
|
|
||||||
"1000/ABC/G3"]},
|
|
||||||
"A2": {"balance": ["1000.0",
|
|
||||||
"1000/ABC/G3"]},
|
|
||||||
"G3": {"balance": ["1000.0"]},
|
|
||||||
"M1": {"balance": ["11000.0",
|
|
||||||
"1200/ABC/G3"],
|
|
||||||
"offers": [["1000/ABC/G3",
|
|
||||||
"10000.0"]],
|
|
||||||
"trusts": ["100000/ABC/G3"]}}},
|
|
||||||
|
|
||||||
"paths_expected": {"T3": {"A": {"alternatives": [{"amount": "1/ABC/A1",
|
|
||||||
"paths": [["ABC/G3|G3",
|
|
||||||
"XRP|$"]]}],
|
|
||||||
"src": "A1",
|
|
||||||
"dst": "A2",
|
|
||||||
"debug":false,
|
|
||||||
"send": "10.0",
|
|
||||||
"via": "ABC"}}}}
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
exports.test_accounts = [
|
|
||||||
'rBmhuVAvi372AerwzwERGjhLjqkMmAwxX',
|
|
||||||
'r4nmQNH4Fhjfh6cHDbvVSsBv7KySbj4cBf',
|
|
||||||
'rGpeQzUWFu4fMhJHZ1Via5aqFC3A5twZUD',
|
|
||||||
'rrnsYgWn13Z28GtRgznrSUsLfMkvsXCZSu',
|
|
||||||
'rJsaPnGdeo7BhMnHjuc3n44Mf7Ra1qkSVJ',
|
|
||||||
'rnYDWQaRdMb5neCGgvFfhw3MBoxmv5LtfH',
|
|
||||||
'r31PEiKfa3y6xTi7uBcSp7F3nDLvVMmqyi',
|
|
||||||
'rfM5xD2CY6XB8o1WsWoJ3ZHGkbHU4NYXr',
|
|
||||||
'r9MB1RNWZChfV3YdLrB3Rm5AoMULewDtiu',
|
|
||||||
'rH15iZg9KFSi7d1usvcsPerUtg7dhpMbk4',
|
|
||||||
'rGWYwGaczQWiduWkccFZKXfp5nDRPqNBNS',
|
|
||||||
'rBU1EP5oMwKxWr1gZnNe7K8GouQTBhzUKs',
|
|
||||||
'rwiTxuknPNeLDYHHLgajRVetKEEwkYhTaQ',
|
|
||||||
'rEbq9pWn2knXFTjjuoNNrKgQeGxhmispMi',
|
|
||||||
'rJfBCsnwSHXjTJ4GH5Ax6Kyw48X977hqyq',
|
|
||||||
'rado7qRcvPpS8ZL8SNg4SG8kBNksHyqoRa',
|
|
||||||
'rNgfurDhqvfsVzLr5ZGB3dJysJhRkvJ79F',
|
|
||||||
'rBtVTnNgX3uR3kyfVyaQ6hjZTdk42ay9Z3',
|
|
||||||
'rND1XyLAU9G2ydhUgmRo4i2kdrSKgYZc31',
|
|
||||||
'rHd21p9Gb834Ri4pzRzGFJ7PjRzymWuBWu',
|
|
||||||
'rhfvFTgpPzCvFPgbA9Nvz42mX92U5ak92m',
|
|
||||||
'rByT8y4BUX1Kcc6xotEabCgwc5PGsbTfSv',
|
|
||||||
'rPBrMbL7uGuteU49b2ibcEBSztoWPX4srr',
|
|
||||||
'rQGRcZn2RyXJL3s7Dfqqzc96Juc7j9j6i9',
|
|
||||||
'rwZrLewGghBMj29kFq7TPw9h9p5eAQ1LUp',
|
|
||||||
'rM9qHXk5uifboWrpu9Wte6Gjzbe974nZ4z',
|
|
||||||
'rBt69hdwMeBgmAtM9YwuFAKxjMqgaBLf3F',
|
|
||||||
'rHpcrpggafr5NNn7mafPhaeB8PMYKXGahp',
|
|
||||||
'rsMKP5MSoyve54o7LgwnZzFfGKzAK8SE5F',
|
|
||||||
'rfN3ccsNxPt41MjHNZRk7ek7q4TpPLqUzL',
|
|
||||||
'rDRWocPjBdhKZSWZezbsnwNpALcJ6GqSGf',
|
|
||||||
'rsmJ4tEMWpcK2qcEMp9uoUv4Ht5Nd6cGTV',
|
|
||||||
'rsxWsnMVRnFozrKJV2VZ1SG6UNbEeHYu16',
|
|
||||||
'r4KoiD6MpaQNPzBka3FRLREkx6EZFwynY4',
|
|
||||||
'rUdovjorVqxyemu5jbpfqA6DYDLdD4eYcj',
|
|
||||||
'r4MrNttmbdiJ7DjWh1MCKW3Kh7kfML46TA',
|
|
||||||
'rndYw73Btcm9Pv9gssZY1S9UcDUPLnpip7',
|
|
||||||
'rh8MnoZmAeWyLx7X8bJZqyjZ48mv1og5PS',
|
|
||||||
'rBoJvU7pcvoy5hjDMMTDNVG4YG85Ed3MEq',
|
|
||||||
'rs4f1BwdNgXAHWLT8rZgW2T1RKSBNY4iDz',
|
|
||||||
'rEmhxShqw42EPm7bY7df5uQySZBkQWnqae',
|
|
||||||
'rNerRdGnbZP6wej22zBdoTUfQKWoMDTH7d',
|
|
||||||
'rDyXvd2WFALJovh76uLe5kUrJ7QLpgmQYE',
|
|
||||||
'rUVi1L28AsCvieXP5pMqPHA9WAfsvCDUjU',
|
|
||||||
'rscuoJN9um2VM4xVv386X5T9APtExFKsbB',
|
|
||||||
'raeeyPs6g5xQn5jyNQbCZ6QeLrqu3FrFvb',
|
|
||||||
'r9UqovJD979WTfNEWXxDU2CVj3K1yo2mqG',
|
|
||||||
'rfRjsAqM1MEuSbWzuLcD6EhSZazgqvZSjy',
|
|
||||||
'rUL4CAxmfpNqDXsQTPCK9ZJ8zHqhUvDWfw',
|
|
||||||
'rP6ZRDFZxjQqeAgdBh1YQSQjWNSASpCL7N',
|
|
||||||
'rsV4AtAqsdyRyZ8s4kaWbM21EPwY5fonx5',
|
|
||||||
'rHaKEMyJErGY6VaKuTj16fSheTp4BRpWG1',
|
|
||||||
'rELHJtahsRpSiSj1nfkY5yKRHCCyRgynw4',
|
|
||||||
'rLYtaGnw4xK86J6mTsLfayyREoYaPPr8Cj',
|
|
||||||
'rD5pAYUfZypmJRSrJnBy3pYo5ApHqw5Jt5',
|
|
||||||
'rfYQrqwNXoA8e2gBDmiHAJAMYrASdQvqDm',
|
|
||||||
'rESt1CB9Sqaj8PYj8SV9x76iwMGBFPzLHb',
|
|
||||||
'rHZWAXh3NdQbyksKzDRLeP9ui32TcqssHZ',
|
|
||||||
'rK9iNjw5SozqKj5zNervwQQTLAgu8V813j',
|
|
||||||
'rUjpFBSmZ8F6cP16VxqpdAXCVCW3rBSZyn',
|
|
||||||
'raPib2vNQAjhh47fVQ7PswKaX1daNBSs2G',
|
|
||||||
'rwhuqz7FppLNvLWdxs7TLLW9UDVztFbw9z',
|
|
||||||
'rJYRe27KXWTjs4P3uu1d4x58Pk5Y13DbUg',
|
|
||||||
'rLFxCuE2GHq38wFUHpswgHJAcz6EUhPimC',
|
|
||||||
'rAaQrzi5satsth174EogwdtdxLZRW5n1h',
|
|
||||||
'rB18Rxdv1aPYtf9nDFpNPJ2HA5BBAqmyoG',
|
|
||||||
'rDSaTM6nCSrc1vH8pPcTAwQpmvb9Y6M2gw',
|
|
||||||
'rpmeCBJUpp9ij1nRM23tRGesWjY7chSHqs',
|
|
||||||
'rwQz7ZkCGdQt7iiuWC3EpbbKwWdL7uLT9C',
|
|
||||||
'rULwRizwxjBwDjcaA44Tbh9MjM5TZFTcLj',
|
|
||||||
'rGMZBEGHbSoegfvqXC2ajXe7RM2Z1LK65N',
|
|
||||||
'rGyFSppE8G7cELAdBU5yL7kWodbw29YdpN',
|
|
||||||
'rJYN3qZsjWhH6bzXX6ZHMZewkMPHeEyGNb',
|
|
||||||
'rEgZVpVSs75eEh6KM4HvcvG64p2TZBL4DC',
|
|
||||||
'rBRfZaqSAkXZYQWBfoy4sN2Q7zZHVGiGwU',
|
|
||||||
'rwg1DRGXLTzQpoWtS35mDowN4PSFQ732eQ',
|
|
||||||
'rKZvkY3T6ahhqkWLTQDSdB1MTKFbbnkqBX',
|
|
||||||
'rGXgpwvaAZ7rBmoSKFUrd83N7WN3Lm4vuX',
|
|
||||||
'rhCMsQ3SJa5Wb4AvBe27hxBQaQQjDG1LG4',
|
|
||||||
'rNtvcU3ePYpZnuYKG77pjRxtKJJ1yrutbm',
|
|
||||||
'rsfK2cTikveAeyvSG8F62c4VFUvZBsH5Rf',
|
|
||||||
'rJT2LrXe7hH1pMEnhEkCMznwtgKuYJS7uz',
|
|
||||||
'rE4Fi4GVjo9NY2g6MtMbitjenUZ21zFoSG',
|
|
||||||
'rp39zV6AFPRJ7yrrL1PSPC1s3oKM2uv2iW',
|
|
||||||
'raCoTW3mhdK6WGUZUSEuvbFM34CSGRRHut',
|
|
||||||
'rKZD9yCV7XAgKq3Rj3a5DmqHHkHBd3ZYao',
|
|
||||||
'rfKtpLEQz8bGCVtQsEzD8cJKeo6AW6J2pD',
|
|
||||||
'rJqNyWJ3rovwkWFdwPhCc6m3jpFogGzRr9',
|
|
||||||
'r41fiShunXNNgJjTjqU9whsjnSYU1BXsjY',
|
|
||||||
'r3uHcWgsNwowCBGF5rhCP5dfdjpYmByBbJ',
|
|
||||||
'r4GZm8WnwX5E9cr8uGiLX42y7KN2NaLqYn',
|
|
||||||
'rKBVsMWErdH443FUkaT799CRVyY9XnVyCK',
|
|
||||||
'razu52accAWWHjxhWEHXNLHWCDhhs1L79p',
|
|
||||||
'rHaL5e3niiikv6KJG4UARqpcjyD5tKNgyV',
|
|
||||||
'rMfcPdGcB5y9zEYw91t3QG2Qj1Z7tqms3S',
|
|
||||||
'r3mqtPNiwkLKisvbnFjM9eC8Rm9JUEXLMD',
|
|
||||||
'rKJGLaJr5SFjZ43BkDeqWKWAtGy1qAAkPf',
|
|
||||||
'rM2zQeTDrt6sMM936Gxh263t1qx3hEb7XK',
|
|
||||||
'rGtqoQJGe4zWenC3yWH9pByTAsGPcjmTU2',
|
|
||||||
'raNUsR5m8jsmb9o9mpNZGGyV86aZUYPunr',
|
|
||||||
'rManQrKu85ezooZ11UmXbxejw5EYHqiUZm',
|
|
||||||
'rKrjCBtwnhQeYkJKrVjDA5CaR5W9NPN2Bb',
|
|
||||||
'rcwyaWqsvGXMRyVW2KHnGUV2MhJVhVx2p',
|
|
||||||
'rLozhAmzcwtEgr1bA28GUh2kbf5kFBMhph',
|
|
||||||
'rJqt8XVcGdpfjZmujoTc6ArHQdZZVhADgM',
|
|
||||||
'rPthXZ93cGAtHJrnAF58vZz6E1js8o6fVf',
|
|
||||||
'rL1LH68PG93BuAeLsiM4cxeBtFmxsoGhRB',
|
|
||||||
'rndqHX6xLknzbgmQPXL4DvhNLRANYf8cDA',
|
|
||||||
'rNEnd2tV3Z1aL5kQmShmHGM3uciSJ4jakF',
|
|
||||||
'rGqPPWnLVWDwWXf495qdxp4um1BTw8TBh5',
|
|
||||||
'rhEDG4mzWGXjjfQp4WMCpZPBDyug5ays9e',
|
|
||||||
'raR6MJ2dYxj1PECUKnLbeamM1k8FnYsY34',
|
|
||||||
'rDcC1S6TRNgTMTgpuSzhAZdTdQJ5EHVf8X',
|
|
||||||
'rLHtg3bWtMKNDYXydd7frGB5pvFbtqzTjg',
|
|
||||||
'rnHhh7qXu2trXuC8aD3Zm7gvM9YetRkEDB',
|
|
||||||
'rfwwUrJztrR7PeKzELEoC1cjcBpsqHmxws',
|
|
||||||
'rw4KzQgZwPJDYX4wHc3NgsLjdR12JGAKsF',
|
|
||||||
'rPCbN5kfEjNgP7TBN3VDJf8eUhv1zCreRL',
|
|
||||||
'r32W6FTsguE3hMv3h79eoNVSJutsDDw6rH',
|
|
||||||
'rBSDvMzyxsea8Zgy8EfryZ7cc1QGrVp9Do',
|
|
||||||
'rfz1TPVJPQYbpSxi6oTiWyhNqy4J1Vz7VL',
|
|
||||||
'rKCyiG5sKxqmKoT2NGT9zS86gS26m9HrQa',
|
|
||||||
'rK7WRdHd6aNqCu2tNbebxYrQkP5u2DouS3',
|
|
||||||
'rLC3xWV4N3ohGxxzcueDrxPLHNqbXrmpUK',
|
|
||||||
'rDE2MwprS1vFvknSKLZJfmxKmbVuE2F85',
|
|
||||||
'r91o1Huejw2qqz37b22Ev8igM4V2Rog1jv',
|
|
||||||
'rEhGRU4P7pVjuxco5BgoXz1974QESKQ1Wy',
|
|
||||||
'raVZ3Uk3qmKqe5aV1ifQsRFL6gU7m25Y2L',
|
|
||||||
'r9p5buUwdMmZ5Um5uK5gC9piRd1fBzMPBN',
|
|
||||||
'r4ruPrbfwnkp5aDSNzQXnWcEK64hJGRnDG',
|
|
||||||
'rwsHCfEwi3PzsfcpcaWLbHXZ2zG5FtNX1J',
|
|
||||||
'r4DkAh7hbTX4E8JPp4kAWkQYazW6236dBB',
|
|
||||||
'rGZSqs5KHQKEJMCaDS3iyWagymixa9zuCv',
|
|
||||||
'r9Nn5Le1bourefaZJ79K2h5VnREFpTqjUw',
|
|
||||||
'rh7NSNpXR9mwWFF8uXvaWjcLVRPfxqQfM9',
|
|
||||||
'rpdxPDQ8mV8gadRcDBh7kNFj1mxYjfddh5',
|
|
||||||
'rMHxgnXgo68vDLUj327YtsHjQyiHGjeccj',
|
|
||||||
'raDd7xZ3RYvKcGiojy9h5UqFV7WULv626i',
|
|
||||||
'rEHzCw3nAuHj66C3xKnGFxV6zDBAssNdSY',
|
|
||||||
'rfvWW9qgyNKYVuJ212himJ7mt6fvkUaS7E',
|
|
||||||
'r9ctoegJfquoj1RHo1bxuW9MjWhbjHyZSA',
|
|
||||||
'rsNPHLq4CgxGoenX67jpuabKe8hx1QvLZk',
|
|
||||||
'rLZouhBz2CpT3ULfJjt193gsLNR4TxjdUS',
|
|
||||||
'rKuUjCThS3DBqfDAupxTvyhkWaskxHoWSP',
|
|
||||||
'rKwSstBmYbKFM3CFw8hvBqsU8pfcZMgNwA',
|
|
||||||
'rBN8iGgpbCc6KYNE36D67TeS6t1YXwmTQc',
|
|
||||||
'rGvBvCyqwn5kPuRUErGD7idtKRb7LtptrS',
|
|
||||||
'r3h89HbdaYJBVd1wfHV6GxDj6Pf2s5iXnF',
|
|
||||||
'rfbUVWFke9JzbK6BhkuayCgX2MVoJvgxBk',
|
|
||||||
'rwTXRBQvPKPMskjp9By1kLJ1pPdRAg77Rz',
|
|
||||||
'rw4ve76xnh8cPwVpE58i46s39MbQ7x1m5W',
|
|
||||||
'r32XzGdUP3GuNJXDGxFM2cYkw7K1KrwXdt' ]
|
|
||||||
Reference in New Issue
Block a user