xrbp 0.1.8 → 0.1.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '096cdf11861212228f99c1f93fca43c0ca503107bbd4602356e55991397a29a9'
4
- data.tar.gz: b6178472d0dd06f47fb38632d5458ea7ffa86720a657e03e3e9c1cc640d2d4e6
3
+ metadata.gz: 80c7817a86dc903b6eb5725bb37ecd562fe6a73b1aef5ee81e2b27ff1aeb50a6
4
+ data.tar.gz: 7003cb99a4488aea91f41d4b8c6bf2fc3bdc577b980d251c858639508f6ae1f1
5
5
  SHA512:
6
- metadata.gz: 67870bc15932d4b2877ac4fffd4bf07221c8ef4834f0a41f72bffa621f246239f5194922c1d9fbb4933d83054eb88c8bffef93f0b95a9940a1389cb74fab69fd
7
- data.tar.gz: 1afd32b1bdf8b9b5be99337da2fc4fd91f29d6dbd8c5deb90a3bf14cbeb9d4a479177c26e4040edf3310b18b11d9d79e1d1532af2855eeefad5b50710211d44b
6
+ metadata.gz: 9792f31b6e62658be6b94f32b3dae6a8fd99a395b5b513d7d6f1cf1e766a121bc074a043b8a1f884c516bda807e06243806f83f7ad2e397655d7ab69b09a5e51
7
+ data.tar.gz: 4e360f3e4464758f0b49158239d898b8b901d094ea5be52faadfaa29dccb4f12120c392bcce1d2c0a03a1058b8345bcce6016abce59ec9dd3524bb75142ec3a6
data/.yardopts CHANGED
@@ -1 +1,2 @@
1
1
  --no-private
2
+ --exclude ripple.proto.rb
@@ -2,18 +2,18 @@ $: << File.expand_path('../../lib', __FILE__)
2
2
  require 'xrbp'
3
3
 
4
4
  # for rocksdb:
5
- #require 'xrbp/nodestore/backends/rocksdb'
6
- #db = XRBP::NodeStore::Backends::RocksDB.new "/home/mmorsi/rippledb/rocksdb/rippledb.beb0"
5
+ require 'xrbp/nodestore/backends/rocksdb'
6
+ db = XRBP::NodeStore::Backends::RocksDB.new "/var/lib/rippled/rocksdb/rippledb.0899"
7
7
 
8
8
  # for nudb:
9
- require 'xrbp/nodestore/backends/nudb'
10
- db = XRBP::NodeStore::Backends::NuDB.new "/var/lib/rippled/nudb/"
9
+ #require 'xrbp/nodestore/backends/nudb'
10
+ #db = XRBP::NodeStore::Backends::NuDB.new "/var/lib/rippled/nudb/"
11
11
 
12
- ledger = "1B927880277CCF943CB4F6BF57A9BCE48F9583A3DD8EEE9A068D63FB6CD99714"
13
- ledger = [ledger].pack("H*")
14
- puts db.ledger(ledger)
12
+ #ledger = "B506ADD630CB707044B4BFFCD943C1395966692A13DD618E5BD0978A006B43BD"
13
+ #ledger = [ledger].pack("H*")
14
+ #puts db.ledger(ledger)
15
15
 
16
16
  #account = "0001bf7468341666f1f47a95e0f4d88e68b5fc7d20d77437cb22954fbbfe6127"
17
- #account = "02c46b3a4130d0a329c47f0da61b829aa5d1ae53c5817e475bcd794e5107be44"
18
- #account = [account].pack("H*")
19
- #puts db.account(account)
17
+ account = "02c46b3a4130d0a329c47f0da61b829aa5d1ae53c5817e475bcd794e5107be44"
18
+ account = [account].pack("H*")
19
+ puts db.account(account)
@@ -2,12 +2,12 @@ $: << File.expand_path('../../lib', __FILE__)
2
2
  require 'xrbp'
3
3
 
4
4
  # for rocksdb:
5
- #require 'xrbp/nodestore/backends/rocksdb'
6
- #db = XRBP::NodeStore::Backends::RocksDB.new "/home/mmorsi/rippledb/rocksdb/rippledb.beb0"
5
+ require 'xrbp/nodestore/backends/rocksdb'
6
+ db = XRBP::NodeStore::Backends::RocksDB.new "/var/lib/rippled/rocksdb/rippledb.0899"
7
7
 
8
8
  # for nudb:
9
- require 'xrbp/nodestore/backends/nudb'
10
- db = XRBP::NodeStore::Backends::NuDB.new "/var/lib/rippled/nudb/"
9
+ #require 'xrbp/nodestore/backends/nudb'
10
+ #db = XRBP::NodeStore::Backends::NuDB.new "/var/lib/rippled/nudb/"
11
11
 
12
12
  db.on :unknown do |hash, node|
13
13
  puts "Unknown #{hash}: #{node}"
@@ -1,5 +1,3 @@
1
- gem 'openssl', '2.1.3'
2
-
3
1
  $: << File.expand_path('../../lib', __FILE__)
4
2
  require 'xrbp'
5
3
 
@@ -9,6 +7,7 @@ puts overlay.handshake.response
9
7
 
10
8
  overlay.read_frames do |frame|
11
9
  puts "Message: #{frame.type_name} (#{frame.size} bytes)"
10
+ # frame.message => protobuf message
12
11
  end
13
12
 
14
13
  overlay.close
@@ -1,3 +1,12 @@
1
+ module XRBP
2
+ # The Crypto module defines methods to create XRPL compliant
3
+ # keys and subsequent entities (accounts, nodes, validators).
4
+ module Crypto
5
+ end # module Crypto
6
+ end # module XRBP
7
+
8
+ require 'xrbp/crypto/seed'
1
9
  require 'xrbp/crypto/key'
2
10
  require 'xrbp/crypto/account'
3
11
  require 'xrbp/crypto/node'
12
+ require 'xrbp/crypto/validator'
@@ -2,16 +2,18 @@ require 'base58'
2
2
 
3
3
  module XRBP
4
4
  module Crypto
5
+ # Generate and new XRPL account.
6
+ #
7
+ # @param key [Symbol, Hash] key type to generate or key itself (optional)
8
+ # @return [Hash] account details containing id and pub/priv key pair
5
9
  def self.account(key=nil)
6
10
  pub = nil
7
11
  if key == :secp256k1 || key.nil?
8
12
  key = Key::secp256k1
9
- key[:type] = :secp256k1
10
13
  pub = key[:public]
11
14
 
12
15
  elsif key == :ed25519
13
16
  key = Key::ed25519
14
- key[:type] = :ed25519
15
17
  pub = "\xED" + key[:public]
16
18
 
17
19
  elsif key.is_a?(Hash)
@@ -29,5 +31,29 @@ module XRBP
29
31
 
30
32
  { :account => Base58.binary_to_base58(account_id + chksum, :ripple) }.merge(key)
31
33
  end
34
+
35
+ # Extract Account ID from Address.
36
+ #
37
+ # @param account [String] Base58 encoded account address
38
+ # @return [String, nil] unique account id or nil if input
39
+ # if not an account
40
+ def self.parse_account(account)
41
+ bin = Base58.base58_to_binary(account, :ripple)
42
+ typ = bin[0]
43
+ chk = bin[-4..-1]
44
+ bin = bin[1...-4]
45
+
46
+ return nil unless typ.unpack("C*").first == Key::TOKEN_TYPES[:account_id]
47
+
48
+ sha256 = OpenSSL::Digest::SHA256.new
49
+ return nil unless sha256.digest(sha256.digest(typ + bin))[0..3] == chk
50
+
51
+ return bin
52
+ end
53
+
54
+ # Return boolean indicating if the specified account is valid
55
+ def self.account?(account)
56
+ parse_account(account) != nil
57
+ end
32
58
  end # module Crypto
33
59
  end # module XRBP
@@ -16,12 +16,8 @@ module XRBP
16
16
 
17
17
  ###
18
18
 
19
- def self.priv
20
- seed = SecureRandom.random_bytes(32)
21
- OpenSSL::Digest::SHA256.new.digest(seed)
22
- end
23
-
24
- def self.secp256k1
19
+ # @return [Hash] new secp256k1 key pair (both public and private components)
20
+ def self.secp256k1(seed=nil)
25
21
  # XXX: the bitcoin secp256k1 implementation (which rippled pulls in / vendors)
26
22
  # has alot of nuances which require special configuration in openssl. For
27
23
  # the time being, mitigate this by pulling in & using the ruby
@@ -34,36 +30,62 @@ module XRBP
34
30
 
35
31
  spk = Secp256k1::PrivateKey.new
36
32
 
37
- # XXX: I'd like to generate the private key first & set,
38
- # but for some reason this doesn't work. When the
39
- # keys are loaded for signing/verification later
40
- # the public key is not able to verify the signature
41
- # generated from the private key set in this way.
42
- # TODO: Investigate
43
- #pk = priv
44
- #spk.set_raw_privkey [pk].pack("H*")
33
+ sd, pk = nil
34
+ if seed
35
+ sd,pk = seed,seed
36
+
37
+ else
38
+ sd = Crypto.seed[:seed]
39
+ pk = Crypto.parse_seed(sd)
40
+ end
41
+
42
+ # FIXME: rippled & ripple-keypairs (& by extension ripple-lib) repeatedly
43
+ # hash seed until certain it is less than the order of the
44
+ # curve, we should do this as well (for security)
45
+ #
46
+ # https://github.com/ripple/rippled/blob/develop/src/ripple/crypto/impl/GenerateDeterministicKey.cpp
47
+ # https://github.com/ripple/ripple-keypairs/blob/master/src/secp256k1.js
48
+ #
49
+ # Also look into if setting raw key here has same effect as
50
+ # secp256k1.mul (as invoked in keypairs)
51
+ sha512 = OpenSSL::Digest::SHA512.new
52
+ pk = sha512.digest(pk)[0..31]
53
+
54
+ spk.set_raw_privkey pk
45
55
 
46
56
  { :public => spk.pubkey.serialize.unpack("H*").first,
47
- :private => spk.send(:serialize) }
57
+ :private => spk.send(:serialize),
58
+ :seed => sd,
59
+ :type => :secp256k1 }
48
60
  end
49
61
 
62
+ # @return [Hash] new ed25519 key pair (both public and private components)
50
63
  def self.ed25519
51
64
  # XXX openssl 1.1.1 needed for EdDSA support:
52
65
  # https://www.openssl.org/blog/blog/2018/09/11/release111/
53
66
  # Until then use this:
54
67
  require "ed25519"
55
68
 
56
- # FIXME: this works for now (eg generates valid keys),
57
- # but we should do this in the same way rippled does:
58
- # Generate private key, then generate corresponding
59
- # Ed25519 public key
60
- key = Ed25519::SigningKey.generate
61
- { :public => key.to_bytes.unpack("H*").first.upcase,
62
- :private => key.verify_key.to_bytes.unpack("H*").first.upcase }
69
+ sd = Crypto.seed[:seed]
70
+ pk = Crypto.parse_seed(sd)
71
+
72
+ sha512 = OpenSSL::Digest::SHA512.new
73
+ pk = sha512.digest(pk)[0..31]
74
+
75
+ key = Ed25519::SigningKey.new(pk)
76
+ { :public => key.verify_key.to_bytes.unpack("H*").first.upcase,
77
+ :private => key.to_bytes.unpack("H*").first.upcase,
78
+ :seed => sd,
79
+ :type => :ed25519 }
63
80
  end
64
81
 
65
82
  ###
66
83
 
84
+ # Sign the digest using the specified key, returning the result
85
+ #
86
+ # @param key [Hash] key to sign digest with
87
+ # @param data [String] data to sign (must be exactly 32 bytes long!)
88
+ # @return [String] signed digest
67
89
  def self.sign_digest(key, data)
68
90
  raise "unknown key" unless key.is_a?(Hash) && key[:type] && key[:private]
69
91
  raise "invalid data" unless data.length == 32
@@ -79,15 +101,57 @@ module XRBP
79
101
  sig_raw = pk.ecdsa_sign data, raw: true
80
102
  return pk.ecdsa_serialize sig_raw
81
103
 
82
- #elsif key[:type] == :ed25519
83
- # TODO
104
+ elsif key[:type] == :ed25519
105
+ # XXX: see note about this library above
106
+ require "ed25519"
107
+
108
+ sd = key[:seed]
109
+ pk = Crypto.parse_seed(sd)
110
+
111
+ sha512 = OpenSSL::Digest::SHA512.new
112
+ pk = sha512.digest(pk)[0..31]
113
+
114
+ pk = Ed25519::SigningKey.new(pk)
115
+ return pk.sign(data)
84
116
  end
85
117
 
86
118
  raise "unknown key type"
87
119
  end
88
120
 
121
+ # Returns bool indicating if data is the result of
122
+ # signing expected value with given key.
123
+ #
124
+ # @param key [Hash] key to use to verify digest
125
+ # @param data [String] signed data
126
+ # @param expected [String] original unsigned data
127
+ # @return [Bool] indicating if signed digest matches
128
+ # original data
89
129
  def self.verify(key, data, expected)
130
+ if key[:type] == :secp256k1
131
+ # XXX: see note about this library above
132
+ require 'secp256k1'
133
+
134
+ pb = Secp256k1::PublicKey.new :pubkey => [key[:public]].pack("H*"),
135
+ :raw => true
136
+ pv = Secp256k1::PrivateKey.new
137
+
138
+ return pb.ecdsa_verify expected,
139
+ pv.ecdsa_deserialize(data), raw: true
140
+
141
+ elsif key[:type] == :ed25519
142
+ # XXX: see note about this library above
143
+ require "ed25519"
144
+
145
+ pk = Ed25519::VerifyKey.new([key[:public]].pack("H*"))
146
+ begin
147
+ return pk.verify(data, expected)
148
+ rescue Ed25519::VerifyError
149
+ return false
150
+ end
151
+ end
152
+
153
+ raise "unknown key type"
90
154
  end
91
- end
155
+ end # module Key
92
156
  end # module Crypto
93
157
  end # module XRBP
@@ -2,14 +2,18 @@ require 'base58'
2
2
 
3
3
  module XRBP
4
4
  module Crypto
5
+ # Generate a new XRPL node.
6
+ #
7
+ # @param key [Symbol, Hash] key type to generate or key itself (optional)
8
+ # @return [Hash] node details containing id and pub/priv key pair
5
9
  def self.node(key=nil)
6
10
  pub = nil
7
11
  if key == :secp256k1 || key.nil?
8
12
  key = Key::secp256k1
9
- key[:type] = :secp256k1
10
13
  pub = key[:public]
11
14
 
12
15
  elsif key.is_a?(Hash)
16
+ key = Key::secp256k1(key[:seed]) if key[:seed]
13
17
  pub = key[:public]
14
18
 
15
19
  else
@@ -23,5 +27,29 @@ module XRBP
23
27
 
24
28
  { :node => Base58.binary_to_base58(node_id + chksum, :ripple) }.merge(key)
25
29
  end
30
+
31
+ # Extract Node ID from Address.
32
+ #
33
+ # @param node [String] Base58 encoded node address
34
+ # @return [String, nil] unique node id or nil if input
35
+ # if not an node
36
+ def self.parse_node(node)
37
+ bin = Base58.base58_to_binary(node, :ripple)
38
+ typ = bin[0]
39
+ chk = bin[-4..-1]
40
+ bin = bin[1...-4]
41
+
42
+ return nil unless typ.unpack("C*").first == Key::TOKEN_TYPES[:node_public]
43
+
44
+ sha256 = OpenSSL::Digest::SHA256.new
45
+ return nil unless sha256.digest(sha256.digest(typ + bin))[0..3] == chk
46
+
47
+ return bin
48
+ end
49
+
50
+ # Return boolean indicating if the specified node is valid
51
+ def self.node?(node)
52
+ parse_node(node) != nil
53
+ end
26
54
  end # module Crypto
27
55
  end # module XRBP
@@ -0,0 +1,58 @@
1
+ require 'base58'
2
+ require 'securerandom'
3
+
4
+ module XRBP
5
+ module Crypto
6
+ # Generate a new XRPL seed.
7
+ #
8
+ # @param key [Symbol] key type to generate (optional)
9
+ # @return [Hash] seed details containing encoded seed and key type
10
+ def self.seed(key=nil)
11
+ prefix = nil
12
+ if key == :secp256k1 || key.nil?
13
+ prefix = [Key::TOKEN_TYPES[:family_seed]]
14
+ key = { :type => :secp256k1 }
15
+
16
+ elsif key == :ed25519
17
+ prefix = [0x01, 0xE1, 0x4B]
18
+ key = { :type => :ed25519 }
19
+
20
+ else
21
+ raise ArgumentError, key
22
+ end
23
+
24
+ sha256 = OpenSSL::Digest::SHA256.new
25
+ base = SecureRandom.random_bytes(16)
26
+ pref = (prefix + base.bytes).pack("C*")
27
+ chk = sha256.digest(sha256.digest(pref))[0..3]
28
+ { :seed => Base58.binary_to_base58(pref + chk, :ripple) }.merge(key)
29
+ end
30
+
31
+ # Extract Seed ID from Encoding.
32
+ #
33
+ # @param seed [String] Base58 encoded seed
34
+ # @return [String, nil] extracted seed or nil
35
+ # if not valid
36
+ def self.parse_seed(seed)
37
+ bin = Base58.base58_to_binary(seed, :ripple)
38
+ typ = bin[0]
39
+ chk = bin[-4..-1]
40
+ bin = bin[1...-4]
41
+
42
+ # TODO also permit ED25519 prefix (?)
43
+ return nil unless typ.unpack("C*").first == Key::TOKEN_TYPES[:family_seed]
44
+
45
+ sha256 = OpenSSL::Digest::SHA256.new
46
+ return nil unless sha256.digest(sha256.digest(typ + bin))[0..3] == chk
47
+
48
+ return nil unless bin.size == 16
49
+
50
+ return bin
51
+ end
52
+
53
+ # Return boolean indicating if the specified seed is valid
54
+ def self.seed?(seed)
55
+ parse_seed(seed) != nil
56
+ end
57
+ end # module Crypto
58
+ end # module XRBP
@@ -0,0 +1,20 @@
1
+ module XRBP
2
+ module Crypto
3
+ # Generate a new XRPL validator. Takes same params as {Crypto#node}
4
+ def self.validator(key=nil)
5
+ return node(key)
6
+ end
7
+
8
+ # Extract Validator ID from Address.
9
+ # Takes same params as {Crypto#parse_node}
10
+ def self.parse_validator(validator)
11
+ return parse_node(validator)
12
+ end
13
+
14
+ # Return bool indicating if Validator is valid.
15
+ # Takes same params as {Crypto#node?}
16
+ def self.validator?(validator)
17
+ return node?(validator)
18
+ end
19
+ end # module Crypto
20
+ end # module XRBP
@@ -4,10 +4,15 @@ require 'lz4-ruby'
4
4
  module XRBP
5
5
  module NodeStore
6
6
  module Backends
7
+ # XRP Ledger Nodestore Decompressor. Currently only the NuDB backend
8
+ # employs compression but decompression is required to read those entries.
9
+ #
7
10
  # Ported from:
8
- # https://github.com/ripple/rippled/blob/develop/src/ripple/nodestore/impl/codec.h
11
+ # {https://github.com/ripple/rippled/blob/develop/src/ripple/nodestore/impl/codec.h codec.h}
9
12
  module Decompressor
10
13
  protected
14
+ # Principle decompression interface, extracts compression type (if any)
15
+ # from data and decompresses accordingly.
11
16
  def decompress(data)
12
17
  type, remaining = read_varint(data)
13
18
  case(type)
@@ -30,7 +35,15 @@ module XRBP
30
35
  end
31
36
 
32
37
  private
33
- # https://github.com/ripple/rippled/blob/develop/src/ripple/nodestore/impl/varint.h
38
+ # This is a custom type/size prefix preprended onto
39
+ # nodestore values.
40
+ #
41
+ # See: {https://github.com/ripple/rippled/blob/develop/src/ripple/nodestore/impl/varint.h varint.h}
42
+ #
43
+ # @param data [String] binary nodestore data
44
+ # @return value prefix and remaining data
45
+ #
46
+ # @private
34
47
  def read_varint(data)
35
48
  bytes = data.bytes
36
49
 
@@ -67,14 +80,22 @@ module XRBP
67
80
 
68
81
  ###
69
82
 
83
+ # Decompresses a LZ4-compressed value
84
+ #
85
+ # @private
70
86
  def decompress_lz4(data)
71
87
  size, remaining = read_varint(data)
72
- o = LZ4::Raw::decompress(remaining, size)[0]
73
- o
88
+ LZ4::Raw::decompress(remaining, size)[0]
74
89
  end
75
90
 
76
91
  ###
77
92
 
93
+ # Decompresses a Compressed Inner Node (Version 1).
94
+ # Inner nodes may contain up to 16 32-byte hashes,
95
+ # though whens stored on disk-the compression algorithm
96
+ # employs a hash-mask to skip storage of unpopulated hashes.
97
+ #
98
+ # @private
78
99
  def decompress_compressed_v1_inner(data)
79
100
  raise if data.size < 34
80
101
 
@@ -84,23 +105,27 @@ module XRBP
84
105
  [Format::HASH_PREFIXES.invert[:inner_node]].pack("H*")
85
106
  .unpack("C*")
86
107
 
108
+ # extract mask indicating which hashes are set
87
109
  bytes = data.bytes
88
110
  mask = bytes[0..1].pack("C*").unpack("S").first
89
111
  bytes = bytes[2..-1]
90
112
 
91
113
  raise "nodeobject codec v1: empty inner node" if mask == 0
92
114
 
115
+ # iterate over hashes...
93
116
  bit = 0x8000
94
117
  i = 16
95
118
  while i > 0
96
119
  i -= 1
97
120
 
121
+ # ...if set in mask, extract from data...
98
122
  if (mask & bit) != 0
99
123
  raise "nodeobject codec v1: short inner node" if bytes.size < 32
100
124
 
101
125
  out += bytes[0..31]
102
126
  bytes = bytes[32..-1]
103
127
 
128
+ # ...otherwise just set to 0
104
129
  else
105
130
  out += Array.new(32) { 0 }
106
131
  end
@@ -111,6 +136,11 @@ module XRBP
111
136
  out.pack("C*")
112
137
  end
113
138
 
139
+ # Decompresses a Compressed Inner Node (Version 2).
140
+ # Similar to Version 1 but contains additional
141
+ # variable length data appended onto the result bytes.
142
+ #
143
+ # @private
114
144
  def decompress_compressed_v2_inner(data)
115
145
  raise if data.size < 67
116
146
 
@@ -120,6 +150,8 @@ module XRBP
120
150
  [Format::HASH_PREFIXES.invert[:inner_node_v2]].pack("H*")
121
151
  .unpack("C*")
122
152
 
153
+ # Same mask / hash extraction as V1
154
+
123
155
  bytes = data.bytes
124
156
  mask = bytes[0..1].pack("C*").unpack("S").first
125
157
  bytes = bytes[2..-1]
@@ -147,6 +179,10 @@ module XRBP
147
179
  bit = bit >> 1
148
180
  end
149
181
 
182
+ ###
183
+
184
+ # Append extra variable-length data onto result
185
+
150
186
  out << depth
151
187
 
152
188
  copy = (depth + 1)/2
@@ -160,6 +196,9 @@ module XRBP
160
196
 
161
197
  ###
162
198
 
199
+ # Decompresses a Full (Uncompressed) Inner Node (Version 1).
200
+ #
201
+ # @private
163
202
  def decompress_full_v1_inner(data)
164
203
  raise if data.size != 512 # 16 32-bit hashes
165
204
 
@@ -170,7 +209,9 @@ module XRBP
170
209
  (out + data[0...512].bytes).pack("C*")
171
210
  end
172
211
 
173
-
212
+ # Decompresses a Full (Uncompressed) Inner Node (Version 2).
213
+ #
214
+ # @private
174
215
  def decompress_full_v2_inner(data)
175
216
  bytes = data.bytes
176
217
  depth = bytes[0]
@@ -8,6 +8,14 @@ require_relative './decompressor'
8
8
  module XRBP
9
9
  module NodeStore
10
10
  module Backends
11
+ # NuDB nodestore backend, faciliates accessing XRP Ledger data
12
+ # in a NuDB database. This module accommodates for compression
13
+ # used in rippled's NuDB nodestore backend implementation
14
+ #
15
+ # @example retrieve data from NuDB backend
16
+ # require 'nodestore/backends/nudb'
17
+ # nudb = NodeStore::Backends::NuDB.new '/var/lib/rippled/db/nudb'
18
+ # puts nudb.ledger('B506ADD630CB707044B4BFFCD943C1395966692A13DD618E5BD0978A006B43BD')
11
19
  class NuDB < DB
12
20
  include Decompressor
13
21
 
@@ -21,16 +29,38 @@ module XRBP
21
29
  open
22
30
  end
23
31
 
32
+ # Retrieve database value for the specified key
33
+ #
34
+ # @param key [String] binary key to lookup
35
+ # @return [String] binary value
24
36
  def [](key)
25
37
  decompress(@store.fetch(key)[0])
26
38
  end
27
39
 
40
+ # Iterate over each database key/value pair,
41
+ # invoking callback. During iteration will
42
+ # emit signals specific to the DB types being
43
+ # parsed
44
+ #
45
+ # @example iterating over NuDB entries
46
+ # nudb.each do |iterator|
47
+ # puts "Key/Value: #{iterator.key}/#{iterator.value}"
48
+ # end
49
+ #
50
+ # @example handling ledgers via event callback
51
+ # nudb.on(:ledger) do |hash, ledger|
52
+ # puts "Ledger #{hash}"
53
+ # pp ledger
54
+ # end
55
+ #
56
+ # # Any Enumerable method that invokes #each will
57
+ # # have intended effect
58
+ # nudb.to_a
28
59
  def each
29
60
  dat = File.join(path, "nudb.dat")
30
61
 
31
62
  RuDB::each(dat) do |key, val|
32
63
  val = decompress(val)
33
- puts key.bytes.join(", ")
34
64
  type, obj = infer_type(val)
35
65
 
36
66
  if type
@@ -48,6 +78,9 @@ puts key.bytes.join(", ")
48
78
 
49
79
  private
50
80
 
81
+ # Create database if it does not exist
82
+ #
83
+ # @private
51
84
  def create!
52
85
  dat = File.join(path, "nudb.dat")
53
86
  key = File.join(path, "nudb.key")
@@ -63,8 +96,9 @@ puts key.bytes.join(", ")
63
96
  :load_factor => 0.5
64
97
  end
65
98
 
66
-
67
-
99
+ # Open existing database
100
+ #
101
+ # @private
68
102
  def open
69
103
  dat = File.join(path, "nudb.dat")
70
104
  key = File.join(path, "nudb.key")
@@ -4,6 +4,13 @@ require "rocksdb"
4
4
  module XRBP
5
5
  module NodeStore
6
6
  module Backends
7
+ # RocksDB nodestore backend, faciliates accessing XRP Ledger data
8
+ # in a RocksDB database.
9
+ #
10
+ # @example retrieve data from RocksDB backend
11
+ # require 'nodestore/backends/rocksdb'
12
+ # rocksdb = NodeStore::Backends::RocksDB.new '/var/lib/rippled/db/rocksdb'
13
+ # puts rocksdb.ledger('B506ADD630CB707044B4BFFCD943C1395966692A13DD618E5BD0978A006B43BD')
7
14
  class RocksDB < DB
8
15
  # cap max open files for performance
9
16
  MAX_OPEN_FILES = 200
@@ -14,10 +21,33 @@ module XRBP
14
21
  :max_open_files => MAX_OPEN_FILES}
15
22
  end
16
23
 
24
+ # Retrieve database value for the specified key
25
+ #
26
+ # @param key [String] binary key to lookup
27
+ # @return [String] binary value
17
28
  def [](key)
18
29
  @db[key]
19
30
  end
20
31
 
32
+ # Iterate over each database key/value pair,
33
+ # invoking callback. During iteration will
34
+ # emit signals specific to the DB types being
35
+ # parsed
36
+ #
37
+ # @example iterating over RocksDB entries
38
+ # rocksdb.each do |iterator|
39
+ # puts "Key/Value: #{iterator.key}/#{iterator.value}"
40
+ # end
41
+ #
42
+ # @example handling account via event callback
43
+ # rocksdb.on(:account) do |hash, account|
44
+ # puts "Account #{hash}"
45
+ # pp account
46
+ # end
47
+ #
48
+ # # Any Enumerable method that invokes #each will
49
+ # # have intended effect
50
+ # rocksdb.to_a
21
51
  def each
22
52
  iterator = @db.new_iterator
23
53
  iterator.seek_to_first
@@ -2,25 +2,46 @@ require 'base58'
2
2
  require 'openssl'
3
3
 
4
4
  module XRBP
5
+ # The NodeStore is the Key/Value DB which rippled persistent stores
6
+ # ledger data. Implemented via a backend configured at run time,
7
+ # the NodeStore is used to store the tree-like structures that
8
+ # consistute the XRP ledger.
9
+ #
10
+ # The Keys and Values stored in the NodeStore are custom binary
11
+ # encodings of tree-node IDs and data. See this module
12
+ # and the others in this directory for specifics on how keys & values
13
+ # are stored and extracted.
5
14
  module NodeStore
15
+
16
+ # Base NodeStore DB module, the client will use this class through
17
+ # specific DB-type subclass.
18
+ #
19
+ # Subclasses should define the <b>[ ]</b> (index) method taking key to
20
+ # lookup, returning corresponding NodeStore value and *each* method,
21
+ # iterating over nodestore values (see existing subclasses for
22
+ # implementation details)
6
23
  class DB
7
24
  include Enumerable
8
25
  include EventEmitter
9
26
 
10
27
  # TODO return nil if db lookup not found
11
28
 
29
+ # Return the NodeStore Ledger for the given lookup hash
12
30
  def ledger(hash)
13
31
  parse_ledger(self[hash])
14
32
  end
15
33
 
34
+ # Return the NodeStore Account for the given lookup hash
16
35
  def account(hash)
17
36
  parse_ledger_entry(self[hash])
18
37
  end
19
38
 
39
+ # Return the NodeStore Transaction for the given lookup hash
20
40
  def tx(hash)
21
41
  parse_tx(self[hash])
22
42
  end
23
43
 
44
+ # Return the NodeStore InnerNode for the given lookup hash
24
45
  def inner_node(hash)
25
46
  parse_inner_node(self[hash])
26
47
  end
@@ -29,6 +50,9 @@ module XRBP
29
50
 
30
51
  private
31
52
 
53
+ # Parsers binary ledger representation into structured ledger.
54
+ #
55
+ # @private
32
56
  def parse_ledger(ledger)
33
57
  obj = Format::LEDGER.decode(ledger)
34
58
  obj['close_time'] = XRBP::from_xrp_time(obj['close_time']).utc
@@ -39,6 +63,11 @@ module XRBP
39
63
  obj
40
64
  end
41
65
 
66
+ # Certain data types are prefixed with an 'encoding' header
67
+ # consisting of a field and/or type. Field, type, and remaining
68
+ # bytes are returned
69
+ #
70
+ # @private
42
71
  def parse_encoding(encoding)
43
72
  enc = encoding.unpack("C").first
44
73
  type = enc >> 4
@@ -59,6 +88,11 @@ module XRBP
59
88
  [[type, field], encoding]
60
89
  end
61
90
 
91
+ # Parses binary ledger entry into hash. Data returned
92
+ # in hash includes ledger entry type prefix, index,
93
+ # and array of parsed fields.
94
+ #
95
+ # @private
62
96
  def parse_ledger_entry(ledger_entry)
63
97
  # validate parsability
64
98
  obj = Format::TYPE_INFER.decode(ledger_entry)
@@ -97,6 +131,9 @@ module XRBP
97
131
 
98
132
  ###
99
133
 
134
+ # Parse and return series of fields from binary data.
135
+ #
136
+ # @private
100
137
  def parse_fields(fields)
101
138
  parsed = {}
102
139
  until fields == "" || fields == "\0" || fields.nil?
@@ -112,6 +149,10 @@ module XRBP
112
149
  return parsed
113
150
  end
114
151
 
152
+ # Parse single field of specified encoding from data.
153
+ # Dispatches to corresponding parsing method when appropriate.
154
+ #
155
+ # @private
115
156
  def parse_field(data, encoding)
116
157
  length = encoding.first
117
158
 
@@ -135,7 +176,6 @@ module XRBP
135
176
  when :vl
136
177
  vl, offset = parse_vl(data)
137
178
  return data[offset..vl+offset-1], data[vl+offset..-1]
138
-
139
179
  when :account
140
180
  return parse_account(data)
141
181
  when :array
@@ -147,12 +187,15 @@ module XRBP
147
187
  when :vector256
148
188
  vl, offset = parse_vl(data)
149
189
  return data[offset..vl+offset-1], data[vl+offset..-1]
150
-
151
190
  end
152
191
 
153
192
  raise
154
193
  end
155
194
 
195
+ # Parse variable length header from data buffer. Returns length
196
+ # extracted from header and the number of bytes in header.
197
+ #
198
+ # @private
156
199
  def parse_vl(data)
157
200
  data = data.bytes
158
201
  first = data.first.to_i
@@ -172,6 +215,9 @@ module XRBP
172
215
  raise
173
216
  end
174
217
 
218
+ # Parse 'Amount' data type from binary data.
219
+ #
220
+ # @private
175
221
  def parse_amount(data)
176
222
  amount = data[0..7].unpack("Q>").first
177
223
  xrp = amount < 0x8000000000000000
@@ -195,6 +241,9 @@ module XRBP
195
241
  :issuer => issuer }, data
196
242
  end
197
243
 
244
+ # Parse 'Account' data type from binary data.
245
+ #
246
+ # @private
198
247
  def parse_account(data, vl=nil)
199
248
  unless vl
200
249
  vl,offset = parse_vl(data)
@@ -209,6 +258,9 @@ module XRBP
209
258
  return Base58.binary_to_base58(acct, :ripple), data[vl..-1]
210
259
  end
211
260
 
261
+ # Parse array of fields from binary data.
262
+ #
263
+ # @private
212
264
  def parse_array(data, encoding)
213
265
  e = Format::ENCODINGS[encoding]
214
266
  return nil, data if e == :end_of_array
@@ -229,6 +281,9 @@ module XRBP
229
281
  return array, data
230
282
  end
231
283
 
284
+ # Parse Object consisting of multiple fields from binary data.
285
+ #
286
+ # @private
232
287
  def parse_object(data, encoding)
233
288
  e = Format::ENCODINGS[encoding]
234
289
  case e
@@ -248,6 +303,9 @@ module XRBP
248
303
  raise "unknown object type"
249
304
  end
250
305
 
306
+ # Parse PathSet from binary data.
307
+ #
308
+ # @private
251
309
  def parse_pathset(data)
252
310
  pathset = [[]]
253
311
  until data == "" || data.nil?
@@ -287,6 +345,9 @@ module XRBP
287
345
 
288
346
  ###
289
347
 
348
+ # Parse Transaction from binary data
349
+ #
350
+ # @private
290
351
  def parse_tx(tx)
291
352
  obj = Format::TYPE_INFER.decode(tx)
292
353
  node_type = Format::NODE_TYPES[obj["node_type"]]
@@ -312,6 +373,9 @@ module XRBP
312
373
  :index => index.pack("C*").unpack("H*").first.upcase }
313
374
  end
314
375
 
376
+ # Parse InnerNode from binary data.
377
+ #
378
+ # @private
315
379
  def parse_inner_node(node)
316
380
  # verify parsability
317
381
  obj = Format::TYPE_INFER.decode(node)
@@ -323,6 +387,9 @@ module XRBP
323
387
 
324
388
  protected
325
389
 
390
+ # Return type and extracted structure from binary data.
391
+ #
392
+ # @private
326
393
  def infer_type(value)
327
394
  obj = Format::TYPE_INFER.decode(value)
328
395
  node_type = Format::NODE_TYPES[obj["node_type"]]
@@ -17,16 +17,20 @@ module XRBP
17
17
  4 => :tx_node
18
18
  }
19
19
 
20
- HASH_PREFIXES = {
21
- "54584E00" => :tx_id,
22
- "534E4400" => :tx_node,
23
- "4D4C4E00" => :leaf_node,
24
- "4D494E00" => :inner_node,
25
- "494E5200" => :inner_node_v2,
26
- "4C575200" => :ledger_master,
27
- "53545800" => :tx_sign,
28
- "56414C00" => :validation,
29
- "50525000" => :proposal
20
+ HASH_PREFIXES = { # ASCII value:
21
+ "54584E00" => :tx_id, # TXN
22
+ "534E4400" => :tx_node, # SND
23
+ "4D4C4E00" => :leaf_node, # MLN
24
+ "4D494E00" => :inner_node, # MIN
25
+ "494E5200" => :inner_node_v2, # INR
26
+ "4C575200" => :ledger_master, # LWR
27
+ "53545800" => :tx_sign, # STX
28
+ "56414C00" => :validation, # VAL
29
+ "50525000" => :proposal # PRP
30
+
31
+ # TODO: :tx_multi_sign # SMT
32
+ # :manifest # MAN
33
+ # :paychan_claim # CLM
30
34
  }
31
35
 
32
36
  ###
@@ -1,3 +1,4 @@
1
1
  require_relative './overlay/connection'
2
2
  require_relative './overlay/handshake'
3
3
  require_relative './overlay/frame'
4
+ require_relative './overlay/messages'
@@ -1,5 +1,23 @@
1
1
  module XRBP
2
+ # The Overlay is the Peer-to-Peer (P2P) network established
3
+ # by rippled node instances to each other. It is what is used
4
+ # to relay transactions and network state as the consensus
5
+ # process is executed.
6
+ #
7
+ # This module facilitates communication with the Overlay P2P
8
+ # network from Ruby.
2
9
  module Overlay
10
+
11
+ # Primary Overlay Connection Interface, use Connection
12
+ # to send and receive Peer-To-Peer data over the Overlay.
13
+ #
14
+ # @example establishing a connection, reading frames
15
+ # overlay = XRBP::Overlay::Connection.new "127.0.0.1", 51235
16
+ # overlay.connect
17
+ #
18
+ # overlay.read_frames do |frame|
19
+ # puts "Message: #{frame.type_name} (#{frame.size} bytes)"
20
+ # end
3
21
  class Connection
4
22
  attr_reader :host, :port
5
23
  attr_accessor :node
@@ -10,14 +28,17 @@ module XRBP
10
28
  @node = Crypto.node
11
29
  end
12
30
 
31
+ # @private
13
32
  def socket
14
33
  @socket ||= TCPSocket.open(host, port)
15
34
  end
16
35
 
36
+ # Indicates if the connection is closed
17
37
  def closed?
18
38
  socket.closed?
19
39
  end
20
40
 
41
+ # @private
21
42
  def ssl_socket
22
43
  @ssl_socket ||= begin
23
44
  ssl_context = OpenSSL::SSL::SSLContext.new
@@ -31,29 +52,38 @@ module XRBP
31
52
  end
32
53
  end
33
54
 
55
+ # @private
34
56
  def handshake
35
57
  @handshake ||= Handshake.new self
36
58
  end
37
59
 
38
60
  ###
39
61
 
62
+ # Initiate new connection to peer
40
63
  def connect
41
64
  ssl_socket.connect
42
65
  handshake.execute!
43
66
  end
44
67
 
45
- def close
68
+ # Close the connection to peer
69
+ def close!
46
70
  ssl_socket.close
47
71
  end
48
72
 
73
+ alias :close :close!
74
+
75
+ # Send raw data via this connection
49
76
  def write(data)
50
77
  ssl_socket.puts(data)
51
78
  end
52
79
 
80
+ # Read raw data from connection
53
81
  def read
54
82
  ssl_socket.gets
55
83
  end
56
84
 
85
+ # Read frames from connection until closed, invoking
86
+ # passed block with each.
57
87
  def read_frames
58
88
  frame = nil
59
89
  remaining = nil
@@ -70,17 +100,15 @@ module XRBP
70
100
 
71
101
  _, remaining = frame << out
72
102
  if frame.complete?
73
- # TODO extra specific protobuf data structure
74
- # from data, set on frame
75
103
  yield frame
76
104
  frame = nil
77
105
  end
78
106
 
79
- # XXX: doesn't feel right to just
80
- # discard remaining, look into this
107
+ # static assertion: should have no more data
108
+ raise unless remaining.nil? || remaining.empty?
81
109
  end
82
110
  end
83
111
  end
84
112
  end # class Connection
85
- end # module WebClient
113
+ end # module Overlay
86
114
  end # module XRBP
@@ -3,6 +3,10 @@ require_relative './ripple.proto'
3
3
 
4
4
  module XRBP
5
5
  module Overlay
6
+ # Overlay Message Frame, prefixes Protobuf based message in
7
+ # with header describing size and type.
8
+ #
9
+ # @private
6
10
  class Frame
7
11
  TYPE_INFER = Bistro.new([
8
12
  'L>', 'size',
@@ -37,14 +41,18 @@ module XRBP
37
41
  @type_name ||= self.class.type_name(type)
38
42
  end
39
43
 
44
+ def message
45
+ @message ||= MESSAGES[type_name].decode(data)
46
+ end
47
+
40
48
  def <<(data)
41
- remaining = size - (@data.size + header_size)
49
+ remaining = size - @data.size
42
50
  @data += data[0..remaining-1]
43
51
  return @data, data[remaining..-1]
44
52
  end
45
53
 
46
54
  def complete?
47
- (@data.size + header_size) == size
55
+ @data.size == size
48
56
  end
49
57
  end # class Frame
50
58
  end # module WebClient
@@ -1,17 +1,24 @@
1
- # XXX this module requires the openssl-ruby gem with the following patches:
2
- # https://github.com/ruby/openssl/pull/250
3
- #
4
- # Otherwise the ssl_socket#finished and #peer_finished methods will
5
- # not be available
6
- #
7
- # Currently the only way to apply this is to checkout openssl-ruby, apply
8
- # the patches, and then rebuild/reinstall the gem locally!
9
-
10
1
  require 'base64'
11
2
  require 'openssl'
12
3
 
13
4
  module XRBP
14
5
  module Overlay
6
+
7
+ # Overlay Connection Handshake, the first message sent from connection
8
+ # initiator to remote endpoint establishing session. Once connection
9
+ # is successfully established subsequent messages will be encapsulated
10
+ # Frames.
11
+ #
12
+ # XXX this module requires the openssl-ruby gem with the following patches:
13
+ # https://github.com/ruby/openssl/pull/250
14
+ #
15
+ # Otherwise the ssl_socket#finished and #peer_finished methods will
16
+ # not be available
17
+ #
18
+ # Currently the only way to apply this is to checkout openssl-ruby, apply
19
+ # the patches, and then rebuild/reinstall the gem locally!
20
+ #
21
+ # @private
15
22
  class Handshake
16
23
  attr_reader :connection, :response
17
24
 
@@ -0,0 +1,27 @@
1
+ module XRBP
2
+ module Overlay
3
+ # Map of Protocol Message Type to Class
4
+ #
5
+ # See {https://github.com/ripple/rippled/blob/develop/src/ripple/overlay/impl/ProtocolMessage.h ProtocolMessage.h}
6
+ MESSAGES = {
7
+ :MTHELLO => Protocol::TMHello,
8
+ :MTMANIFESTS => Protocol::TMManifests,
9
+ :MTPING => Protocol::TMPing,
10
+ :MTCLUSTER => Protocol::TMCluster,
11
+ :MTGET_SHARD_INFO => Protocol::TMGetShardInfo,
12
+ :MTSHARD_INFO => Protocol::TMShardInfo,
13
+ :MTGET_PEER_SHARD_INFO => Protocol::TMGetPeerShardInfo,
14
+ :MTGET_PEERS => Protocol::TMGetPeers,
15
+ :MTPEERS => Protocol::TMPeers,
16
+ :MTENDPOINTS => Protocol::TMEndpoints,
17
+ :MTTRANSACTION => Protocol::TMTransaction,
18
+ :MTGET_LEDGER => Protocol::TMGetLedger,
19
+ :MTLEDGER_DATA => Protocol::TMLedgerData,
20
+ :MTPROPOSE_LEDGER => Protocol::TMProposeSet,
21
+ :MTSTATUS_CHANGE => Protocol::TMStatusChange,
22
+ :MTHAVE_SET => Protocol::TMHaveTransactionSet,
23
+ :MTVALIDATION => Protocol::TMValidation,
24
+ :MTGET_OBJECTS => Protocol::TMGetObjectByHash
25
+ }
26
+ end # module Overlay
27
+ end # module XRBP
@@ -74,6 +74,21 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
74
74
  optional :lastLink, :bool, 4
75
75
  repeated :peerchain, :uint32, 5
76
76
  end
77
+ add_message "protocol.TMLink" do
78
+ optional :nodePubKey, :bytes, 1
79
+ end
80
+ add_message "protocol.TMGetPeerShardInfo" do
81
+ optional :hops, :uint32, 1
82
+ optional :lastLink, :bool, 2
83
+ repeated :peerChain, :message, 3, "protocol.TMLink"
84
+ end
85
+ add_message "protocol.TMPeerShardInfo" do
86
+ optional :shardIndexes, :string, 1
87
+ optional :nodePubKey, :bytes, 2
88
+ optional :endpoint, :string, 3
89
+ optional :lastLink, :bool, 4
90
+ repeated :peerChain, :message, 5, "protocol.TMLink"
91
+ end
77
92
  add_message "protocol.TMTransaction" do
78
93
  optional :rawTransaction, :bytes, 1
79
94
  optional :status, :enum, 2, "protocol.TransactionStatus"
@@ -210,6 +225,8 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
210
225
  value :MTGET_OBJECTS, 42
211
226
  value :MTGET_SHARD_INFO, 50
212
227
  value :MTSHARD_INFO, 51
228
+ value :MTGET_PEER_SHARD_INFO, 52
229
+ value :MTPEER_SHARD_INFO, 53
213
230
  end
214
231
  add_enum "protocol.TransactionStatus" do
215
232
  value :TSZERO, 0
@@ -275,6 +292,9 @@ module Protocol
275
292
  TMCluster = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMCluster").msgclass
276
293
  TMGetShardInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMGetShardInfo").msgclass
277
294
  TMShardInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMShardInfo").msgclass
295
+ TMLink = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMLink").msgclass
296
+ TMGetPeerShardInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMGetPeerShardInfo").msgclass
297
+ TMPeerShardInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMPeerShardInfo").msgclass
278
298
  TMTransaction = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMTransaction").msgclass
279
299
  TMStatusChange = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMStatusChange").msgclass
280
300
  TMProposeSet = Google::Protobuf::DescriptorPool.generated_pool.lookup("protocol.TMProposeSet").msgclass
@@ -1,3 +1,3 @@
1
1
  module XRBP
2
- VERSION = '0.1.8'
2
+ VERSION = '0.1.9'
3
3
  end # module XRBP
@@ -0,0 +1,6 @@
1
+ describe XRBP::Crypto do
2
+ it "generates valid account" do
3
+ acct = described_class.account
4
+ expect(described_class.account?(acct[:account])).to be(true)
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ describe XRBP::Crypto::Key do
2
+ it "generates valid sec256k1 key"
3
+ it "generates valid ed25519 key"
4
+
5
+ it "generates signs and verifies digest" do
6
+ key = described_class.secp256k1
7
+ dat = "ABCDEFGHIJLMNOPQRSTUVWYZ12345678"
8
+ signed = XRBP::Crypto::Key.sign_digest(key, dat)
9
+ expect(XRBP::Crypto::Key.verify(key, signed, dat))
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ describe XRBP::Crypto do
2
+ it "generates valid node" do
3
+ node = described_class.node
4
+ expect(described_class.node?(node[:node])).to be(true)
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ describe XRBP::Crypto do
2
+ it "generates valid seed" do
3
+ seed = described_class.seed
4
+ expect(described_class.seed?(seed[:seed])).to be(true)
5
+ end
6
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xrbp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dev Null Productions
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-17 00:00:00.000000000 Z
11
+ date: 2019-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -196,7 +196,6 @@ files:
196
196
  - examples/paginate.rb
197
197
  - examples/prioritized.rb
198
198
  - examples/round_robin.rb
199
- - examples/sandbox.rb
200
199
  - examples/username.rb
201
200
  - examples/validator.rb
202
201
  - examples/websocket.rb
@@ -207,6 +206,8 @@ files:
207
206
  - lib/xrbp/crypto/account.rb
208
207
  - lib/xrbp/crypto/key.rb
209
208
  - lib/xrbp/crypto/node.rb
209
+ - lib/xrbp/crypto/seed.rb
210
+ - lib/xrbp/crypto/validator.rb
210
211
  - lib/xrbp/dsl.rb
211
212
  - lib/xrbp/dsl/accounts.rb
212
213
  - lib/xrbp/dsl/ledgers.rb
@@ -238,6 +239,7 @@ files:
238
239
  - lib/xrbp/overlay/connection.rb
239
240
  - lib/xrbp/overlay/frame.rb
240
241
  - lib/xrbp/overlay/handshake.rb
242
+ - lib/xrbp/overlay/messages.rb
241
243
  - lib/xrbp/overlay/ripple.proto.rb
242
244
  - lib/xrbp/plugins.rb
243
245
  - lib/xrbp/plugins/base.rb
@@ -286,6 +288,10 @@ files:
286
288
  - spec/helpers/force_serializable.rb
287
289
  - spec/helpers/test_handshake.rb
288
290
  - spec/spec_helper.rb
291
+ - spec/xrbp/crypto/account_spec.rb
292
+ - spec/xrbp/crypto/key_spec.rb
293
+ - spec/xrbp/crypto/node_spec.rb
294
+ - spec/xrbp/crypto/seed_spec.rb
289
295
  - spec/xrbp/websocket/client_spec.rb
290
296
  - spec/xrbp/websocket/command_spec.rb
291
297
  - spec/xrbp/websocket/connection_spec.rb
@@ -1,14 +0,0 @@
1
- $: << File.expand_path('../../lib', __FILE__)
2
- require 'xrbp'
3
- require 'xrbp/nodestore/backends/nudb'
4
-
5
- db = XRBP::NodeStore::Backends::NuDB.new "/var/lib/rippled/nudb/"
6
- store = db.instance_variable_get(:@store)
7
-
8
- key = [47, 126, 65, 231, 47, 167, 3, 91, 161, 174, 133, 152, 2, 230, 171, 139, 209, 40, 100, 217, 100, 131, 160, 49, 186, 119, 31, 84, 75, 116, 125, 81].pack("C*")
9
- val = store.fetch(key).first
10
- #puts val.unpack("C*").join " "
11
- decompressed = db.send(:decompress, val)
12
- puts decompressed.unpack("C*").join " "
13
- type, obj = db.send(:infer_type, decompressed)
14
- puts obj