xrbp 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/nodestore1.rb +3 -1
- data/lib/xrbp/common.rb +6 -0
- data/lib/xrbp/core_ext.rb +21 -0
- data/lib/xrbp/nodestore/format.rb +76 -26
- data/lib/xrbp/nodestore/ledger.rb +46 -14
- data/lib/xrbp/nodestore/parser.rb +47 -14
- data/lib/xrbp/nodestore/protocol/indexes.rb +11 -8
- data/lib/xrbp/nodestore/protocol/issue.rb +15 -0
- data/lib/xrbp/nodestore/protocol/rate.rb +13 -1
- data/lib/xrbp/nodestore/shamap/node_factory.rb +6 -1
- data/lib/xrbp/nodestore/shamap/node_id.rb +2 -2
- data/lib/xrbp/nodestore/sle/st_amount.rb +46 -181
- data/lib/xrbp/nodestore/sle/st_amount_arithmatic.rb +126 -0
- data/lib/xrbp/nodestore/sle/st_amount_comparison.rb +49 -0
- data/lib/xrbp/nodestore/sle/st_amount_conversion.rb +203 -0
- data/lib/xrbp/nodestore/sqldb.rb +69 -4
- data/lib/xrbp/overlay/handshake.rb +1 -1
- data/lib/xrbp/version.rb +1 -1
- data/spec/xrbp/crypto/account_spec.rb +7 -2
- data/spec/xrbp/nodestore/amendments_spec.rb +11 -0
- data/spec/xrbp/nodestore/db_parser.rb +64 -1
- data/spec/xrbp/nodestore/fees_spec.rb +3 -0
- data/spec/xrbp/nodestore/ledger_access.rb +87 -2
- data/spec/xrbp/nodestore/protocol/indexes_spec.rb +43 -0
- data/spec/xrbp/nodestore/protocol/rate_spec.rb +12 -0
- data/spec/xrbp/nodestore/shamap/inner_node_spec.rb +44 -0
- data/spec/xrbp/nodestore/shamap/node_factory_spec.rb +9 -0
- data/spec/xrbp/nodestore/shamap/node_id_spec.rb +6 -0
- data/spec/xrbp/nodestore/shamap/node_spec.rb +25 -0
- data/spec/xrbp/nodestore/shamap_spec.rb +144 -0
- data/spec/xrbp/nodestore/sle/st_amount_arithmatic_spec.rb +7 -0
- data/spec/xrbp/nodestore/sle/st_amount_comparison_spec.rb +11 -0
- data/spec/xrbp/nodestore/sle/st_amount_conversion_spec.rb +64 -0
- data/spec/xrbp/nodestore/sle/st_amount_spec.rb +47 -0
- data/spec/xrbp/nodestore/sle/st_ledger_entry_spec.rb +5 -0
- data/spec/xrbp/nodestore/sle/st_object_spec.rb +29 -0
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90ae30e5619f27c7a1f40b891a0e84b12f2de86bec369391d6e6f39f9a02bc89
|
4
|
+
data.tar.gz: 68365c498a34d0e4c7c3c805b59718f867fa46a6ab2784eab012b22726361212
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0660fab2c5f8248577df45b795d5d6794b03dbb33e88e566ec2e08f477147e74dc92d1703155dc152e103956ac586c38d6e1ad4b02fcd52594f9307f4d97c13
|
7
|
+
data.tar.gz: 3d49ec2789f104a194d6f5b6471cf40c3d0fc51695694157f2c79d189e21fe38ec3a94b2d8cbda9594a87f611f7b3440c5c3f0f9987d12a67782cf22f82c7d0e
|
data/examples/nodestore1.rb
CHANGED
@@ -21,4 +21,6 @@ puts nledger.order_book iou1, iou2
|
|
21
21
|
puts nledger.txs
|
22
22
|
|
23
23
|
require 'xrbp/nodestore/sqldb'
|
24
|
-
|
24
|
+
sql = XRBP::NodeStore::SQLDB.new("/var/lib/rippled/nudb")
|
25
|
+
puts sql.ledgers.hash_for_seq(49340234)
|
26
|
+
puts sql.ledgers.count
|
data/lib/xrbp/common.rb
CHANGED
data/lib/xrbp/core_ext.rb
CHANGED
@@ -59,6 +59,20 @@ class Integer
|
|
59
59
|
end
|
60
60
|
b
|
61
61
|
end
|
62
|
+
|
63
|
+
def byte_string
|
64
|
+
bytes.reverse.pack("C*")
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_int32
|
68
|
+
self & (2**32-1)
|
69
|
+
end
|
70
|
+
|
71
|
+
alias :to_int :to_int32
|
72
|
+
|
73
|
+
def from_xrp_time
|
74
|
+
XRBP.from_xrp_time(self)
|
75
|
+
end
|
62
76
|
end
|
63
77
|
|
64
78
|
# @private
|
@@ -71,3 +85,10 @@ class Array
|
|
71
85
|
fill(x, length...n)
|
72
86
|
end
|
73
87
|
end
|
88
|
+
|
89
|
+
# @private
|
90
|
+
class Time
|
91
|
+
def to_xrp_time
|
92
|
+
XRBP.to_xrp_time(self)
|
93
|
+
end
|
94
|
+
end
|
@@ -383,32 +383,82 @@ module XRBP
|
|
383
383
|
###
|
384
384
|
|
385
385
|
TX_TYPES = {
|
386
|
-
-1 => :
|
387
|
-
0 => :
|
388
|
-
1 => :
|
389
|
-
2 => :
|
390
|
-
3 => :
|
391
|
-
4 => :
|
392
|
-
5 => :
|
393
|
-
6 => :
|
394
|
-
7 => :
|
395
|
-
8 => :
|
396
|
-
|
397
|
-
9 => :
|
398
|
-
|
399
|
-
11 => :
|
400
|
-
12 => :
|
401
|
-
13 => :
|
402
|
-
14 => :
|
403
|
-
15 => :
|
404
|
-
16 => :
|
405
|
-
17 => :
|
406
|
-
18 => :
|
407
|
-
19 => :
|
408
|
-
20 => :
|
409
|
-
|
410
|
-
100 => :
|
411
|
-
101 => :
|
386
|
+
-1 => :Invalid,
|
387
|
+
0 => :Payment,
|
388
|
+
1 => :EscrowCreate,
|
389
|
+
2 => :EscrowFinish,
|
390
|
+
3 => :AccountSet,
|
391
|
+
4 => :EscrowCancel,
|
392
|
+
5 => :SetRegularKey,
|
393
|
+
6 => :NickNameSet, #open
|
394
|
+
7 => :OfferCreate,
|
395
|
+
8 => :OfferCancel,
|
396
|
+
|
397
|
+
9 => :unused,
|
398
|
+
|
399
|
+
11 => :TicketCreate,
|
400
|
+
12 => :TicketCancel,
|
401
|
+
13 => :SignerListSet,
|
402
|
+
14 => :PaymentChannelCreate,
|
403
|
+
15 => :PaymentChannelFund,
|
404
|
+
16 => :PaymentChannelClaim,
|
405
|
+
17 => :CheckCreate,
|
406
|
+
18 => :CheckCash,
|
407
|
+
19 => :CheckCancel,
|
408
|
+
20 => :DepositPreauth,
|
409
|
+
|
410
|
+
100 => :EnableAmendment,
|
411
|
+
101 => :SetFee
|
412
|
+
}
|
413
|
+
|
414
|
+
# https://xrpl.org/transaction-results.html
|
415
|
+
TX_RESULTS = {
|
416
|
+
# tec
|
417
|
+
# https://xrpl.org/tec-codes.html
|
418
|
+
# "Transaction failed, but it was applied to a ledger to apply the transaction cost.
|
419
|
+
# They have numerical values in the range 100 to 199"
|
420
|
+
100 => :tecCLAIM,
|
421
|
+
146 => :tecCRYPTOCONDITION_ERROR,
|
422
|
+
121 => :tecDIR_FULL,
|
423
|
+
149 => :tecDUPLICATE,
|
424
|
+
143 => :tecDST_TAG_NEEDED,
|
425
|
+
148 => :tecEXPIRED,
|
426
|
+
105 => :tecFAILED_PROCESSING,
|
427
|
+
137 => :tecFROZEN,
|
428
|
+
122 => :tecINSUF_RESERVE_LINE,
|
429
|
+
123 => :tecINSUF_RESERVE_OFFER,
|
430
|
+
141 => :tecINSUFFICIENT_RESERVE,
|
431
|
+
144 => :tecINTERNAL,
|
432
|
+
147 => :tecINVARIANT_FAILED,
|
433
|
+
142 => :tecNEED_MASTER_KEY,
|
434
|
+
130 => :tecNO_ALTERNATIVE_KEY,
|
435
|
+
134 => :tecNO_AUTH,
|
436
|
+
124 => :tecNO_DST,
|
437
|
+
125 => :tecNO_DST_INSUF_XRP,
|
438
|
+
140 => :tecNO_ENTRY,
|
439
|
+
133 => :tecNO_ISSUER,
|
440
|
+
150 => :tecKILLED,
|
441
|
+
135 => :tecNO_LINE,
|
442
|
+
126 => :tecNO_LINE_INSUF_RESERVE,
|
443
|
+
127 => :tecNO_LINE_REDUNDANT,
|
444
|
+
139 => :tecNO_PERMISSION,
|
445
|
+
131 => :tecNO_REGULAR_KEY,
|
446
|
+
138 => :tecNO_TARGET,
|
447
|
+
145 => :tecOVERSIZE,
|
448
|
+
132 => :tecOWNERS,
|
449
|
+
128 => :tecPATH_DRY,
|
450
|
+
101 => :tecPATH_PARTIAL,
|
451
|
+
129 => :tecUNFUNDED,
|
452
|
+
102 => :tecUNFUNDED_ADD,
|
453
|
+
104 => :tecUNFUNDED_PAYMENT,
|
454
|
+
103 => :tecUNFUNDED_OFFER,
|
455
|
+
|
456
|
+
# tef, tel, tem, ter transactions _not_
|
457
|
+
# applied to ledger
|
458
|
+
|
459
|
+
# tes
|
460
|
+
# https://xrpl.org/tes-success.html
|
461
|
+
0 => :tesSUCCESS
|
412
462
|
}
|
413
463
|
|
414
464
|
###
|
@@ -43,12 +43,16 @@ module XRBP
|
|
43
43
|
@fees ||= Fees.new
|
44
44
|
end
|
45
45
|
|
46
|
+
# Returns boolean indicating if specified account
|
47
|
+
# is flagged as globally frozen
|
46
48
|
def global_frozen?(account)
|
47
49
|
return false if account == Crypto.xrp_account
|
48
50
|
sle = state_map.read(Indexes::account(account))
|
49
51
|
return sle && sle.flag?(:global_freeze)
|
50
52
|
end
|
51
53
|
|
54
|
+
# Returns boolean indicating if specific account
|
55
|
+
# has frozen trust-line for specified IOU
|
52
56
|
def frozen?(account, iou)
|
53
57
|
return false if iou[:currency] == 'XRP'
|
54
58
|
|
@@ -62,16 +66,19 @@ module XRBP
|
|
62
66
|
:low_freeze)
|
63
67
|
end
|
64
68
|
|
69
|
+
# Return IOU balance which owner account holds
|
65
70
|
def account_holds(owner_id, iou)
|
66
71
|
return xrp_liquid(owner_id, 0) if iou[:currency] == 'XRP'
|
67
72
|
sle = state_map.read(Indexes::line(owner_id, iou))
|
68
73
|
return STAmount.zero if !sle || frozen?(owner_id, iou)
|
69
74
|
|
70
75
|
amount = sle.amount(:balance)
|
71
|
-
amount.negate! if owner_id >
|
76
|
+
amount.negate! if Crypto.account_id(owner_id).to_bn >
|
77
|
+
Crypto.account_id(iou[:account]).to_bn
|
72
78
|
balance_hook(amount)
|
73
79
|
end
|
74
80
|
|
81
|
+
# Returns available (liquid) XRP account holds
|
75
82
|
def xrp_liquid(account, owner_count_adj)
|
76
83
|
sle = state_map.read(Indexes::account(account))
|
77
84
|
return STAmount.zero unless sle
|
@@ -122,8 +129,12 @@ module XRBP
|
|
122
129
|
count
|
123
130
|
end
|
124
131
|
|
132
|
+
# Return TransferRate configured for IOU
|
133
|
+
#
|
134
|
+
# @see {Rate}
|
125
135
|
def transfer_rate(issuer)
|
126
136
|
sle = state_map.read(Indexes::account(issuer))
|
137
|
+
|
127
138
|
return Rate.new sle.field(:uint32,
|
128
139
|
:transfer_rate) if sle &&
|
129
140
|
sle.field?(:transfer_rate)
|
@@ -134,6 +145,10 @@ module XRBP
|
|
134
145
|
|
135
146
|
public
|
136
147
|
|
148
|
+
# TODO: helper method to get first funded high quailty
|
149
|
+
# offer from order book. Also market depth helper
|
150
|
+
|
151
|
+
# Return all offers for the given input/output currency pair
|
137
152
|
def order_book(input, output)
|
138
153
|
offers = []
|
139
154
|
|
@@ -145,6 +160,7 @@ module XRBP
|
|
145
160
|
global_freeze = global_frozen?(output[:account]) ||
|
146
161
|
global_frozen?(input[:account])
|
147
162
|
|
163
|
+
# transfer rate multipled to offer output to pay issuer
|
148
164
|
rate = transfer_rate(output[:account])
|
149
165
|
|
150
166
|
balances = {}
|
@@ -180,28 +196,32 @@ module XRBP
|
|
180
196
|
# Read offer from db and process
|
181
197
|
sle_offer = state_map.read(offer_index)
|
182
198
|
if sle_offer
|
199
|
+
# Direct info from nodestore offer
|
183
200
|
owner_id = sle_offer.account_id(:account)
|
184
201
|
taker_gets = sle_offer.amount(:taker_gets)
|
185
202
|
taker_pays = sle_offer.amount(:taker_pays)
|
186
203
|
|
187
|
-
|
188
|
-
|
204
|
+
# Owner / Output Calculation
|
205
|
+
owner_funds = nil # how much of offer output the owner has
|
206
|
+
first_owner_offer = true # owner_funds returned w/ first owner offer
|
189
207
|
|
208
|
+
# issuer is offering it's own IOU, fully funded
|
190
209
|
if output[:account] == owner_id
|
191
|
-
# issuer is offering it's own IOU, fully funded
|
192
210
|
owner_funds = taker_gets
|
193
211
|
|
212
|
+
# all offers not ours are unfunded
|
194
213
|
elsif global_freeze
|
195
|
-
# all offers not ours are unfunded
|
196
214
|
owner_funds.clear(output)
|
197
215
|
|
198
216
|
else
|
217
|
+
# if we have owner funds cached
|
199
218
|
if balances[owner_id]
|
200
219
|
owner_funds = balances[owner_id]
|
201
220
|
first_owner_offer = false
|
202
221
|
|
222
|
+
# did not find balance in cache
|
203
223
|
else
|
204
|
-
#
|
224
|
+
# lookup from nodestore
|
205
225
|
owner_funds = account_holds(owner_id, output)
|
206
226
|
|
207
227
|
# treat negative funds as zero
|
@@ -209,29 +229,33 @@ module XRBP
|
|
209
229
|
end
|
210
230
|
end
|
211
231
|
|
212
|
-
offer = Hash[sle_offer.fields]
|
213
|
-
taker_gets_funded = nil
|
214
|
-
owner_funds_limit = owner_funds
|
215
|
-
offer_rate = Rate.parity
|
232
|
+
offer = Hash[sle_offer.fields] # copy the offer fields to return
|
233
|
+
taker_gets_funded = nil # how much offer owner will actually be able to fund
|
234
|
+
owner_funds_limit = owner_funds # how much the offer owner has limited by the output transfer fee
|
235
|
+
offer_rate = Rate.parity # offer base output transfer rate
|
216
236
|
|
237
|
+
# Check if transfer fee applies,
|
217
238
|
if rate != Rate.parity && # transfer fee
|
218
239
|
# TODO: provide support for 'taker_id' rpc param:
|
219
240
|
#taker_id != output[:account] && # not taking offers of own IOUs
|
220
241
|
output[:account] != owner_id # offer owner not issuing own funds
|
221
242
|
# Need to charge a transfer fee to offer owner.
|
222
243
|
offer_rate = rate
|
223
|
-
owner_funds_limit = owner_funds / offer_rate.
|
244
|
+
owner_funds_limit = owner_funds / offer_rate.to_amount
|
224
245
|
end
|
225
246
|
|
226
|
-
|
247
|
+
# Check if owner has enough funds to pay it all
|
227
248
|
if owner_funds_limit >= taker_gets
|
228
249
|
# Sufficient funds no shenanigans.
|
229
250
|
taker_gets_funded = taker_gets
|
230
251
|
|
231
252
|
else
|
232
|
-
# Only
|
253
|
+
# Only set these fields, if not fully funded.
|
233
254
|
taker_gets_funded = owner_funds_limit
|
234
255
|
offer[:taker_gets_funded] = taker_gets_funded
|
256
|
+
|
257
|
+
# the account that takes the offer will need to
|
258
|
+
# pay the 'gets' amount actually funded times the dir_rate (quality)
|
235
259
|
offer[:taker_pays_funded] = [taker_pays,
|
236
260
|
taker_gets_funded *
|
237
261
|
dir_rate].min
|
@@ -240,13 +264,21 @@ module XRBP
|
|
240
264
|
offer[:taker_pays_funded].issue = taker_pays.issue
|
241
265
|
end
|
242
266
|
|
267
|
+
# Calculate how much owner will pay after this offer,
|
268
|
+
# if no transfer fee, then the amount funded,
|
269
|
+
# else the minimum of what the owner has or the
|
270
|
+
# amount funded w/ transfer fee
|
243
271
|
owner_pays = (Rate.parity == offer_rate) ?
|
244
272
|
taker_gets_funded :
|
245
273
|
[owner_funds,
|
246
|
-
|
274
|
+
taker_gets_funded *
|
275
|
+
offer_rate.to_amount].min
|
247
276
|
|
277
|
+
# Update balance cache w/ new owner balance
|
248
278
|
balances[owner_id] = owner_funds - owner_pays
|
249
279
|
|
280
|
+
# Set additional params and store the offer
|
281
|
+
|
250
282
|
# include all offers funded and unfunded
|
251
283
|
offer[:quality] = dir_rate
|
252
284
|
offer[:owner_funds] = owner_funds if first_owner_offer
|
@@ -157,6 +157,9 @@ module XRBP
|
|
157
157
|
elsif e == :transaction_type
|
158
158
|
return Format::TX_TYPES[value]
|
159
159
|
|
160
|
+
elsif e == :transaction_result
|
161
|
+
return Format::TX_RESULTS[value]
|
162
|
+
|
160
163
|
elsif e == :ledger_entry_type
|
161
164
|
return Format::LEDGER_ENTRY_TYPE_CODES[value.chr]
|
162
165
|
end
|
@@ -189,22 +192,39 @@ module XRBP
|
|
189
192
|
|
190
193
|
# Parse 'Amount' data type from binary data.
|
191
194
|
#
|
195
|
+
# Stored internally in 64 bits:
|
196
|
+
# - Bit 1 = 0 for XRP, 1 for IOU
|
197
|
+
# - Bit 2 = sign, 0 for negative, 1 for positive
|
198
|
+
#
|
199
|
+
# For XRP:
|
200
|
+
# - Remaining bits = value in drops
|
201
|
+
#
|
202
|
+
# For IOU:
|
203
|
+
# - Next 8 bits = Exponent
|
204
|
+
# - Next 54 bits = Mantissa
|
205
|
+
# Where value = mantissa * (10 ^ exponent)
|
206
|
+
# Note: 97 is added to exponent when serializing and subtracted when parsing so
|
207
|
+
# that effective nominal exponent is always in range of -96 to 80
|
208
|
+
#
|
192
209
|
# @see https://developers.ripple.com/currency-formats.html
|
210
|
+
# @see STAmount(SerialIter& sit, SField const& name);
|
211
|
+
# @see {STAmount#from_wire}
|
193
212
|
#
|
194
213
|
# @protected
|
195
214
|
def parse_amount(data)
|
196
215
|
amount = data[0..7].unpack("Q>").first
|
197
|
-
xrp = amount < 0x8000000000000000
|
198
|
-
|
199
|
-
# FIXME : is sign/neg right (?)
|
200
216
|
|
201
|
-
|
202
|
-
|
217
|
+
# native eg, xrp
|
218
|
+
is_xrp = (amount & STAmount::NOT_NATIVE) == 0
|
219
|
+
if is_xrp
|
220
|
+
is_pos = (amount & STAmount::POS_NATIVE) != 0
|
221
|
+
return STAmount.new(:issue => NodeStore.xrp_issue,
|
222
|
+
:mantissa => amount & ~STAmount::POS_NATIVE), data[8..-1] if is_pos
|
203
223
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
224
|
+
return STAmount.new(:issue => NodeStore.xrp_issue,
|
225
|
+
:mantissa => amount,
|
226
|
+
:neg => true), data[8..-1]
|
227
|
+
end
|
208
228
|
|
209
229
|
data = data[8..-1]
|
210
230
|
currency = Format::CURRENCY_CODE.decode(data)
|
@@ -213,12 +233,25 @@ module XRBP
|
|
213
233
|
data = data[Format::CURRENCY_CODE.size..-1]
|
214
234
|
issuer, data = parse_account(data, 20)
|
215
235
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
236
|
+
issue = Issue.new(currency, issuer)
|
237
|
+
|
238
|
+
exp = (amount >> (64 - 10)).to_int
|
239
|
+
mant = (amount & ~(1023 << (64 - 10)))
|
240
|
+
|
241
|
+
if mant
|
242
|
+
neg = (exp & 256) == 0
|
243
|
+
exp = (exp & 255) - 97
|
244
|
+
|
245
|
+
sle = STAmount.new(:issue => issue,
|
246
|
+
:neg => neg,
|
247
|
+
:mantissa => mant,
|
248
|
+
:exponent => exp)
|
249
|
+
|
250
|
+
return sle, data
|
251
|
+
end
|
220
252
|
|
221
|
-
|
253
|
+
raise unless exp == 512
|
254
|
+
return STAmount.new(:issue => issue)
|
222
255
|
end
|
223
256
|
|
224
257
|
# Parse 'Account' data type from binary data.
|
@@ -4,15 +4,14 @@ module XRBP
|
|
4
4
|
module Indexes
|
5
5
|
|
6
6
|
def self.get_quality(base)
|
7
|
-
# FIXME:
|
7
|
+
# FIXME: assuming native platform is big endian,
|
8
8
|
# need to account for all platforms
|
9
|
-
base[-8..-1].
|
9
|
+
base[-8..-1].to_bn
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.get_quality_next(base)
|
13
13
|
nxt = "10000000000000000".to_i(16)
|
14
|
-
(base.to_bn + nxt).
|
15
|
-
.reverse.pack("C*")
|
14
|
+
(base.to_bn + nxt).byte_string
|
16
15
|
end
|
17
16
|
|
18
17
|
###
|
@@ -45,6 +44,14 @@ module XRBP
|
|
45
44
|
sha512.digest[0..31]
|
46
45
|
end
|
47
46
|
|
47
|
+
# TODO: Account Owner Dir from id
|
48
|
+
def self.owner_dir(id)
|
49
|
+
end
|
50
|
+
|
51
|
+
# TODO: Offer Index for account id and seq
|
52
|
+
def self.offer_index(id, seq)
|
53
|
+
end
|
54
|
+
|
48
55
|
# Trust line for account/iou
|
49
56
|
def self.line(account, iou)
|
50
57
|
account = Crypto.account_id(account)
|
@@ -68,10 +75,6 @@ module XRBP
|
|
68
75
|
sha512.digest[0..31]
|
69
76
|
end
|
70
77
|
|
71
|
-
# TODO: order book dir hash for ledger
|
72
|
-
def self.order_book_dir()
|
73
|
-
end
|
74
|
-
|
75
78
|
# Order book index for given input/output
|
76
79
|
def self.order_book(input, output)
|
77
80
|
input = Hash[input]
|