xrbp 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
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