xrbp 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/examples/nodestore1.rb +12 -7
  3. data/lib/xrbp/core_ext.rb +27 -0
  4. data/lib/xrbp/crypto/account.rb +28 -3
  5. data/lib/xrbp/nodestore.rb +6 -0
  6. data/lib/xrbp/nodestore/amendments.rb +13 -0
  7. data/lib/xrbp/nodestore/backends/decompressor.rb +8 -6
  8. data/lib/xrbp/nodestore/backends/nudb.rb +2 -0
  9. data/lib/xrbp/nodestore/backends/rocksdb.rb +1 -0
  10. data/lib/xrbp/nodestore/db.rb +5 -387
  11. data/lib/xrbp/nodestore/fees.rb +19 -0
  12. data/lib/xrbp/nodestore/format.rb +72 -1
  13. data/lib/xrbp/nodestore/ledger.rb +272 -0
  14. data/lib/xrbp/nodestore/parser.rb +407 -0
  15. data/lib/xrbp/nodestore/protocol.rb +5 -0
  16. data/lib/xrbp/nodestore/protocol/currency.rb +11 -0
  17. data/lib/xrbp/nodestore/protocol/indexes.rb +109 -0
  18. data/lib/xrbp/nodestore/protocol/issue.rb +26 -0
  19. data/lib/xrbp/nodestore/protocol/quality.rb +10 -0
  20. data/lib/xrbp/nodestore/protocol/rate.rb +21 -0
  21. data/lib/xrbp/nodestore/shamap.rb +447 -0
  22. data/lib/xrbp/nodestore/shamap/errors.rb +8 -0
  23. data/lib/xrbp/nodestore/shamap/inner_node.rb +98 -0
  24. data/lib/xrbp/nodestore/shamap/item.rb +14 -0
  25. data/lib/xrbp/nodestore/shamap/node.rb +49 -0
  26. data/lib/xrbp/nodestore/shamap/node_factory.rb +120 -0
  27. data/lib/xrbp/nodestore/shamap/node_id.rb +83 -0
  28. data/lib/xrbp/nodestore/shamap/tagged_cache.rb +20 -0
  29. data/lib/xrbp/nodestore/shamap/tree_node.rb +21 -0
  30. data/lib/xrbp/nodestore/sle.rb +4 -0
  31. data/lib/xrbp/nodestore/sle/st_account.rb +8 -0
  32. data/lib/xrbp/nodestore/sle/st_amount.rb +226 -0
  33. data/lib/xrbp/nodestore/sle/st_ledger_entry.rb +24 -0
  34. data/lib/xrbp/nodestore/sle/st_object.rb +46 -0
  35. data/lib/xrbp/nodestore/sqldb.rb +23 -0
  36. data/lib/xrbp/nodestore/uint.rb +7 -0
  37. data/lib/xrbp/version.rb +1 -1
  38. data/spec/xrbp/nodestore/backends/nudb_spec.rb +3 -1
  39. data/spec/xrbp/nodestore/backends/rocksdb_spec.rb +1 -1
  40. data/spec/xrbp/nodestore/{backends/db_parser.rb → db_parser.rb} +2 -2
  41. data/spec/xrbp/nodestore/ledger_access.rb +17 -0
  42. metadata +30 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6390bfb57eaa26b5285cb3f3c3fb10d85d0a3a81e09e3c3b1e52eff6d4a00514
4
- data.tar.gz: b616a6a4324fbd34ec8e77529c2827fca77949f635a0785ab33d8ca867baccc2
3
+ metadata.gz: cdd7b83c144366a77c0a68287e2ae511fa2878ef5b3be0e0f24b0b4d9e6a1be5
4
+ data.tar.gz: 1db244c92cefaca23244dd7a20cbb89c0d9e2fc25ab10659483aaa8187f0f117
5
5
  SHA512:
6
- metadata.gz: 6b96064684b5ef84f089808649e4b281e9f055610543deec66b8d09122c7a7b545da95f44b55e60a8e73e6402ec3d03f52cfc79ea9ee85bacc9e66003dbf0b01
7
- data.tar.gz: 1f9f959987d864d4500ffc5ba2172c5341a9705a3eec9e3af09de88bfa9bf5f8feabbae0a7030db3437af75348a924b2535abb0b4661192aa44b3d5e300715df
6
+ metadata.gz: 42cdd0d6b998b3550a89233b90c86676fe9e56f7a4981cfad96f209fb3272ae2f669f5b16de399318596d13fb9c0fc2b087fa968155a4f30f211fed46cce74c4
7
+ data.tar.gz: ee8e543e9e04557f8e8355dbd4f56a19f9176ba8e3f24c87db128298f38caa0386bf3763180bee734c94f7e91aaba3341c4689b4f7d4a53b3d4d0fa49d22b6d9
@@ -9,11 +9,16 @@ db = XRBP::NodeStore::Backends::RocksDB.new "/var/lib/rippled/rocksdb/rippledb.0
9
9
  #require 'xrbp/nodestore/backends/nudb'
10
10
  #db = XRBP::NodeStore::Backends::NuDB.new "/var/lib/rippled/nudb/"
11
11
 
12
- #ledger = "B506ADD630CB707044B4BFFCD943C1395966692A13DD618E5BD0978A006B43BD"
13
- #ledger = [ledger].pack("H*")
14
- #puts db.ledger(ledger)
12
+ ledger = "32E073D7E4D722D956F7FDE095F756FBB86DC9CA487EB0D9ABF5151A8D88F912"
13
+ ledger = [ledger].pack("H*")
14
+ puts db.ledger(ledger)
15
15
 
16
- #account = "0001bf7468341666f1f47a95e0f4d88e68b5fc7d20d77437cb22954fbbfe6127"
17
- account = "02c46b3a4130d0a329c47f0da61b829aa5d1ae53c5817e475bcd794e5107be44"
18
- account = [account].pack("H*")
19
- puts db.account(account)
16
+ gw1 = 'razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA'
17
+ iou1 = {:currency => 'XRP', :account => XRBP::Crypto.xrp_account}
18
+ iou2 = {:currency => 'CNY', :account => gw1}
19
+ nledger = XRBP::NodeStore::Ledger.new(:db => db, :hash => ledger)
20
+ puts nledger.order_book iou1, iou2
21
+ puts nledger.txs
22
+
23
+ require 'xrbp/nodestore/sqldb'
24
+ puts XRBP::NodeStore::SQLDB.new("/var/lib/rippled/").ledger_hash_for_seq(49340234)
@@ -29,6 +29,22 @@ class String
29
29
  def to_bn
30
30
  bytes.inject(0) { |bn, b| (bn << 8) | b }
31
31
  end
32
+
33
+ def all?(&bl)
34
+ each_char { |c| return false unless bl.call(c) }
35
+ return true
36
+ end
37
+
38
+ def zero?
39
+ return self == "\0" if size == 1
40
+ all? { |c| c.zero? }
41
+ end
42
+
43
+ # scan(regex) will not work as we need to process
44
+ # binary strings (\n's seem to trip scan up)
45
+ def chunk(size)
46
+ ((self.length + size - 1) / size).times.collect { |i| self[i * size, size] }
47
+ end
32
48
  end
33
49
 
34
50
  # @private
@@ -44,3 +60,14 @@ class Integer
44
60
  b
45
61
  end
46
62
  end
63
+
64
+ # @private
65
+ class Array
66
+ def rjust!(n, x)
67
+ insert(0, *Array.new([0, n-length].max, x))
68
+ end
69
+
70
+ def ljust!(n, x)
71
+ fill(x, length...n)
72
+ end
73
+ end
@@ -2,12 +2,13 @@ require 'base58'
2
2
 
3
3
  module XRBP
4
4
  module Crypto
5
- # Generate and new XRPL account.
5
+ # Generate a new XRPL account.
6
6
  #
7
7
  # @param key [Symbol, Hash] key type to generate or key itself (optional)
8
8
  # @return [Hash] account details containing id and pub/priv key pair
9
9
  def self.account(key=nil)
10
10
  pub = nil
11
+ account_id = nil
11
12
  if key == :secp256k1 || key.nil?
12
13
  key = Key::secp256k1
13
14
  pub = key[:public]
@@ -17,21 +18,45 @@ module XRBP
17
18
  pub = "\xED" + key[:public]
18
19
 
19
20
  elsif key.is_a?(Hash)
20
- pub = key[:public]
21
+ if key[:account_id]
22
+ account_id = key[:account_id]
23
+ elsif key[:public]
24
+ pub = key[:public]
25
+ end
21
26
 
22
27
  else
23
28
  pub = key
24
29
  key = {:public => pub}
25
30
  end
26
31
 
32
+ raise "must specify pub or account_id" unless pub || account_id
33
+
27
34
  sha256 = OpenSSL::Digest::SHA256.new
28
35
  ripemd160 = OpenSSL::Digest::RIPEMD160.new
29
- account_id = [Key::TOKEN_TYPES[:account_id]].pack("C") + ripemd160.digest(sha256.digest([pub].pack("H*")))
36
+ account_id = [Key::TOKEN_TYPES[:account_id]].pack("C") + ripemd160.digest(sha256.digest([pub].pack("H*"))) unless account_id
30
37
  chksum = sha256.digest(sha256.digest(account_id))[0..3]
31
38
 
32
39
  { :account => Base58.binary_to_base58(account_id + chksum, :ripple) }.merge(key)
33
40
  end
34
41
 
42
+ # Account Zero: https://xrpl.org/accounts.html#special-addresses
43
+ def self.xrp_account
44
+ @xrp_account ||= account(:account_id => ([0] * 21).pack("C*"))[:account]
45
+ end
46
+
47
+ # Account One: https://xrpl.org/accounts.html#special-addresses
48
+ def self.no_account
49
+ @no_account ||= account(:account_id => ([0] * 20 + [1]).pack("C*"))[:account]
50
+ end
51
+
52
+ # Return the account id for the specified XRP account.
53
+ # This is a simpler version of {parse_account} that just
54
+ # returns the binary account, _skipping_ the token and
55
+ # checksum verifications.
56
+ def self.account_id(account)
57
+ Base58.base58_to_binary(account, :ripple)[1..-5]
58
+ end
59
+
35
60
  # Extract Account ID from Address.
36
61
  #
37
62
  # @param account [String] Base58 encoded account address
@@ -1,4 +1,10 @@
1
+ require_relative './nodestore/uint'
1
2
  require_relative './nodestore/format'
3
+ require_relative './nodestore/sle'
4
+ require_relative './nodestore/shamap'
5
+ require_relative './nodestore/ledger'
6
+
7
+ require_relative './nodestore/protocol'
2
8
 
3
9
  require_relative './nodestore/db'
4
10
 
@@ -0,0 +1,13 @@
1
+ module XRBP
2
+ module NodeStore
3
+ module Amendments
4
+ def fix1141_time
5
+ @fix1141_time ||= Time.new(2016, 6, 1, 17, 0, 0, 0)
6
+ end
7
+
8
+ def fix1141?(time)
9
+ time > fix1141_time
10
+ end
11
+ end
12
+ end # module NodeStore
13
+ end # module XRBP
@@ -102,8 +102,8 @@ module XRBP
102
102
  out = [0, 0, 0, 0,
103
103
  0, 0, 0, 0,
104
104
  Format::NODE_TYPES[:unknown]] +
105
- [Format::HASH_PREFIXES.invert[:inner_node]].pack("H*")
106
- .unpack("C*")
105
+ [Format::HASH_PREFIXES[:inner_node]].pack("H*")
106
+ .unpack("C*")
107
107
 
108
108
  # extract mask indicating which hashes are set
109
109
  bytes = data.bytes
@@ -147,8 +147,8 @@ module XRBP
147
147
  out = [0, 0, 0, 0,
148
148
  0, 0, 0, 0,
149
149
  Format::NODE_TYPES[:unknown]] +
150
- [Format::HASH_PREFIXES.invert[:inner_node_v2]].pack("H*")
151
- .unpack("C*")
150
+ [Format::HASH_PREFIXES[:inner_node_v2]].pack("H*")
151
+ .unpack("C*")
152
152
 
153
153
  # Same mask / hash extraction as V1
154
154
 
@@ -205,7 +205,8 @@ module XRBP
205
205
  out = [0, 0, 0, 0,
206
206
  0, 0, 0, 0,
207
207
  Format::NODE_TYPES[:unknown]] +
208
- [Format::HASH_PREFIXES.invert[:inner_node]].pack("H*").unpack("C*")
208
+ [Format::HASH_PREFIXES[:inner_node]].pack("H*")
209
+ .unpack("C*")
209
210
  (out + data[0...512].bytes).pack("C*")
210
211
  end
211
212
 
@@ -223,7 +224,8 @@ module XRBP
223
224
  out = [0, 0, 0, 0,
224
225
  0, 0, 0, 0,
225
226
  Format::NODE_TYPES[:unknown]] +
226
- [Format::HASH_PREFIXES.invert[:inner_node_v2]].pack("H*").unpack("C*")
227
+ [Format::HASH_PREFIXES[:inner_node_v2]].pack("H*")
228
+ .unpack("C*")
227
229
 
228
230
  out += bytes[0..511]
229
231
  bytes = bytes[512..-1]
@@ -76,6 +76,8 @@ module XRBP
76
76
  :value => val)
77
77
  yield iterator
78
78
  end
79
+
80
+ return self
79
81
  end
80
82
 
81
83
  private
@@ -67,6 +67,7 @@ module XRBP
67
67
  end
68
68
 
69
69
  iterator.close
70
+ return self
70
71
  end
71
72
  end # class RocksDB
72
73
  end # module Backends
@@ -1,6 +1,8 @@
1
1
  require 'base58'
2
2
  require 'openssl'
3
3
 
4
+ require_relative './parser'
5
+
4
6
  module XRBP
5
7
  # The NodeStore is the Key/Value DB which rippled persistent stores
6
8
  # ledger data. Implemented via a backend configured at run time,
@@ -24,6 +26,9 @@ module XRBP
24
26
  include Enumerable
25
27
  include EventEmitter
26
28
 
29
+ # NodeStore Parser
30
+ include Parser
31
+
27
32
  # Return the NodeStore Ledger for the given lookup hash
28
33
  def ledger(hash)
29
34
  val = self[hash]
@@ -56,393 +61,6 @@ module XRBP
56
61
  return nil if val.nil?
57
62
  parse_inner_node(val)
58
63
  end
59
-
60
- ###
61
-
62
- private
63
-
64
- # Parsers binary ledger representation into structured ledger.
65
- #
66
- # @private
67
- def parse_ledger(ledger)
68
- obj = Format::LEDGER.decode(ledger)
69
- obj['close_time'] = XRBP::from_xrp_time(obj['close_time']).utc
70
- obj['parent_close_time'] = XRBP::from_xrp_time(obj['parent_close_time']).utc
71
- obj['parent_hash'].upcase!
72
- obj['tx_hash'].upcase!
73
- obj['account_hash'].upcase!
74
- obj
75
- end
76
-
77
- # Certain data types are prefixed with an 'encoding' header
78
- # consisting of a field and/or type. Field, type, and remaining
79
- # bytes are returned
80
- #
81
- # @private
82
- def parse_encoding(encoding)
83
- enc = encoding.unpack("C").first
84
- type = enc >> 4
85
- field = enc & 0xF
86
- encoding = encoding[1..-1]
87
-
88
- if type == 0
89
- type = encoding.unpack("C").first
90
- encoding = encoding[1..-1]
91
- end
92
-
93
- if field == 0
94
- field = encoding.unpack("C").first
95
- encoding = encoding[1..-1]
96
- end
97
-
98
- type = Format::SERIALIZED_TYPES[type]
99
- [[type, field], encoding]
100
- end
101
-
102
- # Parses binary ledger entry into hash. Data returned
103
- # in hash includes ledger entry type prefix, index,
104
- # and array of parsed fields.
105
- #
106
- # @private
107
- def parse_ledger_entry(ledger_entry)
108
- # validate parsability
109
- obj = Format::TYPE_INFER.decode(ledger_entry)
110
- node_type = Format::NODE_TYPE_CODES[obj["node_type"]]
111
- hash_prefix = Format::HASH_PREFIXES[obj["hash_prefix"].upcase]
112
- raise unless node_type == :account_node &&
113
- hash_prefix == :leaf_node
114
-
115
- # discard node type, and hash prefix
116
- ledger_entry = ledger_entry[13..-1]
117
-
118
- # verify encoding
119
- encoding, ledger_entry = parse_encoding(ledger_entry)
120
- raise "Invalid Ledger Entry" unless Format::ENCODINGS[encoding] == :ledger_entry_type
121
- ledger_entry = ledger_entry.bytes
122
-
123
- # first byte after encoding is ledger entry type prefix
124
- prefix = ledger_entry[0..1].pack("C*")
125
-
126
- # last 32 bytes is entry index
127
- index = ledger_entry[-32..-1].pack("C*")
128
- .unpack("H*")
129
- .first
130
- .upcase
131
-
132
- # remaining bytes are serialized object
133
- fields, remaining = parse_fields(ledger_entry[2...-32].pack("C*"))
134
- raise unless remaining.empty?
135
-
136
- # TODO instantiate class corresponding to type &
137
- # populate attributes w/ fields (?)
138
-
139
- { :type => Format::LEDGER_ENTRY_TYPE_CODES[prefix[1]],
140
- :index => index,
141
- :fields => fields }
142
- end
143
-
144
- ###
145
-
146
- # Parse and return series of fields from binary data.
147
- #
148
- # @private
149
- def parse_fields(fields)
150
- parsed = {}
151
- until fields == "" || fields == "\0" || fields.nil?
152
- encoding, fields = parse_encoding(fields)
153
- return parsed if encoding.first.nil?
154
-
155
- e = Format::ENCODINGS[encoding]
156
- value, fields = parse_field(fields, encoding)
157
- break unless value
158
- parsed[e] = convert_field(encoding, value)
159
- end
160
-
161
- return parsed, fields
162
- end
163
-
164
- # Parse single field of specified encoding from data.
165
- # Dispatches to corresponding parsing method when appropriate.
166
- #
167
- # @private
168
- def parse_field(data, encoding)
169
- length = encoding.first
170
-
171
- case length
172
- when :uint8
173
- return data.unpack("C").first, data[1..-1]
174
- when :uint16
175
- return data.unpack("S>").first, data[2..-1]
176
- when :uint32
177
- return data.unpack("L>").first, data[4..-1]
178
- when :uint64
179
- return data.unpack("Q>").first, data[8..-1]
180
- when :hash128
181
- return data.unpack("H32").first, data[16..-1]
182
- when :hash160
183
- return data.unpack("H40").first, data[20..-1]
184
- when :hash256
185
- return data.unpack("H64").first, data[32..-1]
186
- when :amount
187
- return parse_amount(data)
188
- when :vl
189
- vl, offset = parse_vl(data)
190
- return data[offset..vl+offset-1], data[vl+offset..-1]
191
- when :account
192
- return parse_account(data)
193
- when :array
194
- return parse_array(data, encoding)
195
- when :object
196
- return parse_object(data, encoding)
197
- when :pathset
198
- return parse_pathset(data)
199
- when :vector256
200
- vl, offset = parse_vl(data)
201
- return data[offset..vl+offset-1], data[vl+offset..-1]
202
- end
203
-
204
- raise
205
- end
206
-
207
- def convert_field(encoding, value)
208
- e = Format::ENCODINGS[encoding]
209
-
210
- if encoding.first == :vl
211
- return value.unpack("H*").first
212
-
213
- elsif e == :transaction_type
214
- return Format::TX_TYPES[value]
215
-
216
- elsif e == :ledger_entry_type
217
- return Format::LEDGER_ENTRY_TYPE_CODES[value.chr]
218
- end
219
-
220
- value
221
- end
222
-
223
- # Parse variable length header from data buffer. Returns length
224
- # extracted from header and the number of bytes in header.
225
- #
226
- # @private
227
- def parse_vl(data)
228
- data = data.bytes
229
- first = data.first.to_i
230
- return first, 1 if first <= 192
231
-
232
- data = data[1..-1]
233
- second = data.first.to_i
234
- if first <= 240
235
- return (193+(first-193)*256+second), 2
236
-
237
- elsif first <= 254
238
- data = data[1..-1]
239
- third = data.first.to_i
240
- return (12481 + (first-241)*65536 + second*256 + third), 3
241
- end
242
-
243
- raise
244
- end
245
-
246
- # Parse 'Amount' data type from binary data.
247
- #
248
- # @see https://developers.ripple.com/currency-formats.html
249
- #
250
- # @private
251
- def parse_amount(data)
252
- amount = data[0..7].unpack("Q>").first
253
- xrp = amount < 0x8000000000000000
254
- return (amount & 0x3FFFFFFFFFFFFFFF), data[8..-1] if xrp
255
-
256
- sign = (amount & 0x4000000000000000) >> 62 # 0 = neg / 1 = pos
257
- exp = (amount & 0x3FC0000000000000) >> 54
258
- mant = (amount & 0x003FFFFFFFFFFFFF)
259
-
260
- data = data[8..-1]
261
- currency = Format::CURRENCY_CODE.decode(data)
262
- currency = currency["iso_code"].pack("C*")
263
-
264
- data = data[Format::CURRENCY_CODE.size..-1]
265
- issuer, data = parse_account(data, 20)
266
-
267
- amount = (sign == 0 ? -1 : 1) * mant * 10 ** (exp-97)
268
-
269
- return { :amount => amount,
270
- :currency => currency,
271
- :issuer => issuer }, data
272
- end
273
-
274
- # Parse 'Account' data type from binary data.
275
- #
276
- # @private
277
- def parse_account(data, vl=nil)
278
- unless vl
279
- vl,offset = parse_vl(data)
280
- data = data[offset..-1]
281
- end
282
-
283
- acct = "\0" + data[0..vl-1]
284
- sha256 = OpenSSL::Digest::SHA256.new
285
- digest = sha256.digest(sha256.digest(acct))[0..3]
286
- acct += digest
287
- acct.force_encoding(Encoding::BINARY) # required for Base58 gem
288
- return Base58.binary_to_base58(acct, :ripple), data[vl..-1]
289
- end
290
-
291
- # Parse array of fields from binary data.
292
- #
293
- # @private
294
- def parse_array(data, encoding)
295
- e = Format::ENCODINGS[encoding]
296
- return nil, data if e == :end_of_array
297
-
298
- array = []
299
- until data == "" || data.nil?
300
- aencoding, data = parse_encoding(data)
301
- break if aencoding.first.nil?
302
-
303
- e = Format::ENCODINGS[aencoding]
304
- break if e == :end_of_array
305
-
306
- value, data = parse_field(data, aencoding)
307
- break unless value
308
- array << value
309
- end
310
-
311
- return array, data
312
- end
313
-
314
- # Parse Object consisting of multiple fields from binary data.
315
- #
316
- # @private
317
- def parse_object(data, encoding)
318
- e = Format::ENCODINGS[encoding]
319
- case e
320
- when :end_of_object
321
- return nil, data
322
-
323
- when :signer, :signer_entry,
324
- :majority, :memo,
325
- :modified_node, :created_node, :deleted_node,
326
- :previous_fields, :final_fields, :new_fields
327
- # TODO instantiate corresponding classes (?)
328
- return parse_fields(data)
329
-
330
- #else:
331
- end
332
-
333
- raise "unknown object type: #{e}"
334
- end
335
-
336
- # Parse PathSet from binary data.
337
- #
338
- # @private
339
- def parse_pathset(data)
340
- pathset = [[]]
341
- until data == "" || data.nil?
342
- segment = data.unpack("C").first
343
- data = data[1..-1]
344
- return pathset, data if segment == 0x00 # end of path
345
-
346
- if segment == 0xFF # path boundry
347
- pathset << []
348
- else
349
- account, current, issuer = nil
350
-
351
- path = {}
352
-
353
- if (segment & 0x01) != 0 # path account
354
- account, data = parse_account(data, 20)
355
- path[:account] = account
356
- end
357
-
358
- if (segment & 0x10) != 0 # path currency
359
- currency = Format::CURRENCY_CODE.decode(data)
360
- currency = currency["iso_code"].pack("C*")
361
- data = data[Format::CURRENCY_CODE.size..-1]
362
- path[:currency] = currency
363
- end
364
-
365
- if (segment & 0x20) != 0 # path issuer
366
- issuer, data = parse_account(data, 20)
367
- path[:issuer] = issuer
368
- end
369
-
370
- pathset.last << path
371
- end
372
- end
373
-
374
- return pathset, data
375
- end
376
-
377
- ###
378
-
379
- # Parse Transaction from binary data
380
- #
381
- # @private
382
- def parse_tx(tx)
383
- obj = Format::TYPE_INFER.decode(tx)
384
- node_type = Format::NODE_TYPE_CODES[obj["node_type"]]
385
- hash_prefix = Format::HASH_PREFIXES[obj["hash_prefix"].upcase]
386
- raise unless node_type == :tx_node &&
387
- hash_prefix == :tx_node
388
-
389
- # discard node type, and hash prefix
390
- tx = tx[13..-1]
391
-
392
- # get node length
393
- vl, offset = parse_vl(tx)
394
- node, _tx = tx.bytes[offset..vl+offset-1], tx.bytes[vl+offset..-1]
395
- node, _remaining = parse_fields(node.pack("C*"))
396
-
397
- # get meta length
398
- vl, offset = parse_vl(_tx.pack("C*"))
399
- meta, index = _tx[offset..vl+offset-1], _tx[vl+offset..-1]
400
- meta, _remaining = parse_fields(meta.pack("C*"))
401
-
402
- { :node => node,
403
- :meta => meta,
404
- :index => index.pack("C*").unpack("H*").first.upcase }
405
- end
406
-
407
- # Parse InnerNode from binary data.
408
- #
409
- # @private
410
- def parse_inner_node(node)
411
- # verify parsability
412
- obj = Format::TYPE_INFER.decode(node)
413
- hash_prefix = Format::HASH_PREFIXES[obj["hash_prefix"].upcase]
414
- raise unless hash_prefix == :inner_node
415
-
416
- node = Format::INNER_NODE.decode(node)
417
- node['node_type'] = Format::NODE_TYPE_CODES[node['node_type']]
418
- node
419
- end
420
-
421
- protected
422
-
423
- # Return type and extracted structure from binary data.
424
- #
425
- # @private
426
- def infer_type(value)
427
- obj = Format::TYPE_INFER.decode(value)
428
- node_type = Format::NODE_TYPE_CODES[obj["node_type"]]
429
- hash_prefix = Format::HASH_PREFIXES[obj["hash_prefix"].upcase]
430
-
431
- if hash_prefix == :inner_node
432
- return :inner_node, parse_inner_node(value)
433
-
434
- elsif node_type == :account_node
435
- return :ledger_entry, parse_ledger_entry(value)
436
-
437
- elsif node_type == :tx_node
438
- return :tx, parse_tx(value)
439
-
440
- elsif node_type == :ledger
441
- return :ledger, parse_ledger(value)
442
- end
443
-
444
- return nil
445
- end
446
64
  end # class DB
447
65
  end # module NodeStore
448
66
  end # module XRBP