Class: XRBP::NodeStore::Ledger

Inherits:
Object
  • Object
show all
Includes:
Amendments, Parser
Defined in:
lib/xrbp/nodestore/ledger.rb

Instance Method Summary collapse

Methods included from Amendments

#fix1141?, #fix1141_time

Constructor Details

#initialize(args = {}) ⇒ Ledger

Returns a new instance of Ledger.


12
13
14
15
16
17
18
19
20
# File 'lib/xrbp/nodestore/ledger.rb', line 12

def initialize(args={})
  @db = args[:db]
  @hash = args[:hash]

  if @hash
    state_map.fetch_root [info["account_hash"]].pack("H*")
       tx_map.fetch_root [info["tx_hash"]].pack("H*")
  end
end

Instance Method Details

#order_book(input, output) ⇒ Object

Return all offers for the given input/output currency pair


152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/xrbp/nodestore/ledger.rb', line 152

def order_book(input, output)
  offers = []

  # Start at order book index
  # Stop after max order book quality
  tip_index = Indexes::order_book(input, output)
   book_end = Indexes::get_quality_next(tip_index)

  global_freeze = global_frozen?(output[:account]) ||
                  global_frozen?(input[:account])

  # transfer rate multipled to offer output to pay issuer
  rate = transfer_rate(output[:account])

     balances = {}
         done = false # set true when we cannot traverse anymore
       direct = true  # set true when we need to find next dir
    offer_dir = nil   # current directory being travred
     dir_rate = nil   # current directory quality
  offer_index = nil   # index of current offer being processed
   book_entry = nil   # index of next offer directory record
  until done
    if direct
      direct = false
      # Return first index after tip
      ledger_index = state_map.succ(tip_index, book_end)
      if ledger_index
        # retrieve offer_dir SLE from db
        offer_dir = state_map.read(ledger_index)
      else
        offer_dir = nil
      end

      if !offer_dir
        done = true
      else
        # Set new tip, get first offer at new tip
        tip_index = offer_dir.key
        dir_rate = STAmount.from_quality(Indexes::get_quality(tip_index))
        offer_index, offer_dir, book_entry = state_map.cdir_first(tip_index)
      end
    end

    if !done
      # Read offer from db and process
      sle_offer = state_map.read(offer_index)
      if sle_offer
        # Direct info from nodestore offer
          owner_id = sle_offer.(:account)
        taker_gets = sle_offer.amount(:taker_gets)
        taker_pays = sle_offer.amount(:taker_pays)

        # Owner / Output Calculation
              owner_funds = nil  # how much of offer output the owner has
        first_owner_offer = true # owner_funds returned w/ first owner offer

        # issuer is offering it's own IOU, fully funded
        if output[:account] == owner_id
          owner_funds = taker_gets

        # all offers not ours are unfunded
        elsif global_freeze
          owner_funds.clear(output)

        else
          # if we have owner funds cached
          if balances[owner_id]
            owner_funds = balances[owner_id]
            first_owner_offer = false

          # did not find balance in cache
          else
            # lookup from nodestore
            owner_funds = (owner_id, output)

            # treat negative funds as zero
            owner_funds.clear if owner_funds < STAmount.zero
          end
        end

        offer = Hash[sle_offer.fields]   # copy the offer fields to return
        taker_gets_funded = nil          # how much offer owner will actually be able to fund
        owner_funds_limit = owner_funds  # how much the offer owner has limited by the output transfer fee
        offer_rate = Rate.parity         # offer base output transfer rate

        # Check if transfer fee applies,
        if            rate != Rate.parity      && # transfer fee
                 # TODO: provide support for 'taker_id' rpc param:
                 #taker_id != output[:account] && # not taking offers of own IOUs
          output[:account] != owner_id            # offer owner not issuing own funds
            # Need to charge a transfer fee to offer owner.
            offer_rate = rate
            owner_funds_limit = owner_funds / offer_rate.to_amount
        end

        # Check if owner has enough funds to pay it all
        if owner_funds_limit >= taker_gets
          # Sufficient funds no shenanigans.
          taker_gets_funded = taker_gets

        else
          # Only set these fields, if not fully funded.
          taker_gets_funded = owner_funds_limit
          offer[:taker_gets_funded] = taker_gets_funded

          # the account that takes the offer will need to
          # pay the 'gets' amount actually funded times the dir_rate (quality)
          offer[:taker_pays_funded] = [taker_pays,
                                       taker_gets_funded *
                                                dir_rate].min

          # XXX: done in multiply operation in rippled
          offer[:taker_pays_funded].issue = taker_pays.issue
        end

        # Calculate how much owner will pay after this offer,
        # if no transfer fee, then the amount funded,
        # else the minimum of what the owner has or the
        # amount funded w/ transfer fee
        owner_pays = (Rate.parity == offer_rate) ?
                               taker_gets_funded :
                                     [owner_funds,
                                taker_gets_funded *
                             offer_rate.to_amount].min

        # Update balance cache w/ new owner balance
        balances[owner_id] = owner_funds - owner_pays

        # Set additional params and store the offer

        # include all offers funded and unfunded
        offer[:quality] = dir_rate
        offer[:owner_funds] = owner_funds if first_owner_offer
        offers << offer

      else
        puts "missing offer"
      end

      # Retrieve next offer in offer_dir,
      # updating offer_index, offer_dir, book_entry appropriately
      offer_index, offer_dir, book_entry = *state_map.cdir_next(tip_index, offer_dir, book_entry)

      # if next offer not retrieved find next record after tip
      direct = true if !offer_index
    end
  end

  return offers
end

#txsObject


22
23
24
# File 'lib/xrbp/nodestore/ledger.rb', line 22

def txs
  @txs ||= tx_map.collect { |tx| parse_tx_inner(tx.data) }
end