xrbp 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/crawl_nodes.rb +1 -1
- data/examples/nodestore1.rb +14 -0
- data/examples/nodestore2.rb +42 -0
- data/examples/p2p.rb +14 -0
- data/lib/xrbp.rb +3 -0
- data/lib/xrbp/common.rb +6 -0
- data/lib/xrbp/core_ext.rb +22 -0
- data/lib/xrbp/crypto.rb +3 -0
- data/lib/xrbp/crypto/account.rb +33 -0
- data/lib/xrbp/crypto/key.rb +93 -0
- data/lib/xrbp/crypto/node.rb +27 -0
- data/lib/xrbp/model/node.rb +2 -1
- data/lib/xrbp/nodestore.rb +7 -0
- data/lib/xrbp/nodestore/backends/nudb.rb +1 -0
- data/lib/xrbp/nodestore/backends/rocksdb.rb +43 -0
- data/lib/xrbp/nodestore/db.rb +324 -0
- data/lib/xrbp/nodestore/format.rb +297 -0
- data/lib/xrbp/overlay.rb +3 -0
- data/lib/xrbp/overlay/connection.rb +86 -0
- data/lib/xrbp/overlay/frame.rb +51 -0
- data/lib/xrbp/overlay/handshake.rb +78 -0
- data/lib/xrbp/overlay/ripple.proto.rb +306 -0
- data/lib/xrbp/version.rb +1 -1
- data/lib/xrbp/webclient/connection.rb +6 -1
- metadata +61 -2
@@ -0,0 +1,297 @@
|
|
1
|
+
require "bistro"
|
2
|
+
|
3
|
+
module XRBP
|
4
|
+
module NodeStore
|
5
|
+
module Format
|
6
|
+
NODE_TYPES = {
|
7
|
+
1 => :ledger,
|
8
|
+
2 => :tx,
|
9
|
+
3 => :account_node,
|
10
|
+
4 => :tx_node
|
11
|
+
}
|
12
|
+
|
13
|
+
HASH_PREFIXES = {
|
14
|
+
"54584E00" => :tx_id,
|
15
|
+
"534E4400" => :tx_node,
|
16
|
+
"4D4C4E00" => :leaf_node,
|
17
|
+
"4D494E00" => :inner_node,
|
18
|
+
"4C575200" => :ledger_master,
|
19
|
+
"53545800" => :tx_sign,
|
20
|
+
"56414C00" => :validation,
|
21
|
+
"50525000" => :proposal
|
22
|
+
}
|
23
|
+
|
24
|
+
###
|
25
|
+
|
26
|
+
SERIALIZED_TYPES = {
|
27
|
+
1 => :uint16,
|
28
|
+
2 => :uint32,
|
29
|
+
3 => :uint64,
|
30
|
+
4 => :hash128,
|
31
|
+
5 => :hash256,
|
32
|
+
6 => :amount,
|
33
|
+
7 => :vl,
|
34
|
+
8 => :account,
|
35
|
+
14 => :object,
|
36
|
+
15 => :array,
|
37
|
+
16 => :uint8,
|
38
|
+
17 => :hash160,
|
39
|
+
18 => :pathset,
|
40
|
+
19 => :vector256
|
41
|
+
}
|
42
|
+
|
43
|
+
ENCODINGS = {
|
44
|
+
# 16-bit unsigned integers (common)
|
45
|
+
[:uint16, 1] => :ledger_entry_type,
|
46
|
+
[:uint16, 2] => :transaction_type,
|
47
|
+
[:uint16, 3] => :signer_weight,
|
48
|
+
|
49
|
+
# 32-bit unsigned integers (common)
|
50
|
+
[:uint32, 2] => :flags,
|
51
|
+
[:uint32, 3] => :source_tag,
|
52
|
+
[:uint32, 4] => :sequence,
|
53
|
+
[:uint32, 5] => :previous_txn_lgr_seq,
|
54
|
+
[:uint32, 6] => :ledger_sequence,
|
55
|
+
[:uint32, 7] => :close_time,
|
56
|
+
[:uint32, 8] => :parent_close_time,
|
57
|
+
[:uint32, 9] => :signing_time,
|
58
|
+
[:uint32, 10] => :expiration,
|
59
|
+
[:uint32, 11] => :transfer_rate,
|
60
|
+
[:uint32, 12] => :wallet_size,
|
61
|
+
[:uint32, 13] => :owner_count,
|
62
|
+
[:uint32, 14] => :destination_tag,
|
63
|
+
|
64
|
+
# 32-bit unsigned integers (uncommon)
|
65
|
+
[:uint32, 16] => :high_quality_in,
|
66
|
+
[:uint32, 17] => :high_quality_out,
|
67
|
+
[:uint32, 18] => :low_quality_in,
|
68
|
+
[:uint32, 19] => :low_quality_out,
|
69
|
+
[:uint32, 20] => :quality_in,
|
70
|
+
[:uint32, 21] => :quality_out,
|
71
|
+
[:uint32, 22] => :stamp_escrow,
|
72
|
+
[:uint32, 23] => :bond_amount,
|
73
|
+
[:uint32, 24] => :load_fee,
|
74
|
+
[:uint32, 25] => :offer_sequence,
|
75
|
+
|
76
|
+
[:uint32, 26] => :first_ledger_sequence,
|
77
|
+
[:uint32, 27] => :last_ledger_sequence,
|
78
|
+
|
79
|
+
[:uint32, 28] => :transaction_index,
|
80
|
+
[:uint32, 29] => :operation_limit,
|
81
|
+
|
82
|
+
[:uint32, 30] => :reference_fee_units,
|
83
|
+
[:uint32, 31] => :reserve_base,
|
84
|
+
[:uint32, 32] => :reserve_increment,
|
85
|
+
[:uint32, 33] => :set_flag,
|
86
|
+
[:uint32, 34] => :clear_flag,
|
87
|
+
[:uint32, 35] => :signer_quorum,
|
88
|
+
[:uint32, 36] => :cancel_after,
|
89
|
+
[:uint32, 37] => :finish_after,
|
90
|
+
[:uint32, 38] => :signer_list_id,
|
91
|
+
[:uint32, 39] => :settle_delay,
|
92
|
+
|
93
|
+
# 64-bit unsigned integers (common)
|
94
|
+
[:uint64, 1] => :index_next,
|
95
|
+
[:uint64, 2] => :index_previous,
|
96
|
+
[:uint64, 3] => :book_node,
|
97
|
+
[:uint64, 4] => :owner_node,
|
98
|
+
[:uint64, 5] => :base_fee,
|
99
|
+
[:uint64, 6] => :exchange_rate,
|
100
|
+
[:uint64, 7] => :low_node,
|
101
|
+
[:uint64, 8] => :high_node,
|
102
|
+
|
103
|
+
# 128-bit (common)
|
104
|
+
[:hash128, 1] => :email_hash,
|
105
|
+
|
106
|
+
# 256-bit (common)
|
107
|
+
[:hash256, 1] => :ledger_hash,
|
108
|
+
[:hash256, 2] => :parent_hash,
|
109
|
+
[:hash256, 3] => :tx_hash,
|
110
|
+
[:hash256, 4] => :account_hash,
|
111
|
+
[:hash256, 5] => :previous_txn_id,
|
112
|
+
[:hash256, 6] => :ledger_index,
|
113
|
+
[:hash256, 7] => :wallet_locator,
|
114
|
+
[:hash256, 8] => :root_index,
|
115
|
+
[:hash256, 9] => :account_txn_id,
|
116
|
+
|
117
|
+
# 256-bit (uncommon)
|
118
|
+
[:hash256, 16] => :book_directory,
|
119
|
+
[:hash256, 17] => :invoice_id,
|
120
|
+
[:hash256, 18] => :nickname,
|
121
|
+
[:hash256, 19] => :amendment,
|
122
|
+
[:hash256, 20] => :ticket_id,
|
123
|
+
[:hash256, 21] => :digest,
|
124
|
+
[:hash256, 22] => :channel,
|
125
|
+
[:hash256, 24] => :check_id,
|
126
|
+
|
127
|
+
# currency amount (common)
|
128
|
+
[:amount, 1] => :amount,
|
129
|
+
[:amount, 2] => :balance,
|
130
|
+
[:amount, 3] => :limit_amount,
|
131
|
+
[:amount, 4] => :taker_pays,
|
132
|
+
[:amount, 5] => :taker_gets,
|
133
|
+
[:amount, 6] => :low_limit,
|
134
|
+
[:amount, 7] => :high_limit,
|
135
|
+
[:amount, 8] => :fee,
|
136
|
+
[:amount, 9] => :send_max,
|
137
|
+
[:amount, 10] => :deliver_min,
|
138
|
+
|
139
|
+
# currency amount (uncommon)
|
140
|
+
[:amount, 16] => :minimum_offer,
|
141
|
+
[:amount, 17] => :ripple_escrow,
|
142
|
+
[:amount, 18] => :delivered_amount,
|
143
|
+
|
144
|
+
# variable length (common)
|
145
|
+
[:vl, 1] => :public_key,
|
146
|
+
[:vl, 2] => :message_key,
|
147
|
+
[:vl, 3] => :signing_pub_key,
|
148
|
+
[:vl, 4] => :txn_signature,
|
149
|
+
[:vl, 5] => :generator,
|
150
|
+
[:vl, 6] => :signature,
|
151
|
+
[:vl, 7] => :domain,
|
152
|
+
[:vl, 8] => :fund_code,
|
153
|
+
[:vl, 9] => :remove_code,
|
154
|
+
[:vl, 10] => :expire_code,
|
155
|
+
[:vl, 11] => :create_code,
|
156
|
+
[:vl, 12] => :memo_type,
|
157
|
+
[:vl, 13] => :memo_data,
|
158
|
+
[:vl, 14] => :memo_format,
|
159
|
+
|
160
|
+
# variable length (uncommon)
|
161
|
+
[:vl, 16] => :fulfillment,
|
162
|
+
[:vl, 17] => :condition,
|
163
|
+
[:vl, 18] => :master_signature,
|
164
|
+
|
165
|
+
# account
|
166
|
+
[:account, 1] => :account,
|
167
|
+
[:account, 2] => :owner,
|
168
|
+
[:account, 3] => :destination,
|
169
|
+
[:account, 4] => :issuer,
|
170
|
+
[:account, 7] => :target,
|
171
|
+
[:account, 8] => :regular_key,
|
172
|
+
|
173
|
+
# inner object
|
174
|
+
[:object, 1] => :end_of_object,
|
175
|
+
[:object, 2] => :transaction_metadata,
|
176
|
+
[:object, 3] => :created_node,
|
177
|
+
[:object, 4] => :deleted_node,
|
178
|
+
[:object, 5] => :modified_node,
|
179
|
+
[:object, 6] => :previous_fields,
|
180
|
+
[:object, 7] => :final_fields,
|
181
|
+
[:object, 8] => :new_fields,
|
182
|
+
[:object, 9] => :template_entry,
|
183
|
+
[:object, 10] => :memo,
|
184
|
+
[:object, 11] => :signer_entry,
|
185
|
+
|
186
|
+
# inner object (uncommon)
|
187
|
+
[:object, 16] => :signer,
|
188
|
+
[:object, 18] => :majority,
|
189
|
+
|
190
|
+
# array of objects
|
191
|
+
[:array, 1] => :end_of_array,
|
192
|
+
[:array, 2] => :signing_accounts,
|
193
|
+
[:array, 3] => :signers,
|
194
|
+
[:array, 4] => :signer_entries,
|
195
|
+
[:array, 5] => :template,
|
196
|
+
[:array, 6] => :necessary,
|
197
|
+
[:array, 7] => :sufficient,
|
198
|
+
[:array, 8] => :affected_nodes,
|
199
|
+
[:array, 9] => :memos,
|
200
|
+
|
201
|
+
# array of objects (uncommon)
|
202
|
+
[:array, 16] => :majorities,
|
203
|
+
|
204
|
+
# 8-bit unsigned integers (common)
|
205
|
+
[:uint8, 1] => :close_resolution,
|
206
|
+
[:uint8, 2] => :method,
|
207
|
+
[:uint8, 3] => :transaction_result,
|
208
|
+
|
209
|
+
# 8-bit unsigned integers (uncommon)
|
210
|
+
[:uint8, 16] => :tick_size,
|
211
|
+
|
212
|
+
# 160-bit (common)
|
213
|
+
[:hash160, 1] => :taker_pays_currency,
|
214
|
+
[:hash160, 2] => :taker_pays_issuer,
|
215
|
+
[:hash160, 3] => :taker_gets_currency,
|
216
|
+
[:hash160, 4] => :taker_gets_issuer,
|
217
|
+
|
218
|
+
# path set
|
219
|
+
[:pathset, 1] => :paths,
|
220
|
+
|
221
|
+
# vector of 256-bit
|
222
|
+
[:vector256, 1] => :indexes,
|
223
|
+
[:vector256, 2] => :hashes,
|
224
|
+
[:vector256, 3] => :amendments,
|
225
|
+
}
|
226
|
+
|
227
|
+
###
|
228
|
+
|
229
|
+
TYPE_INFER = Bistro.new([
|
230
|
+
'H16', nil, # unused
|
231
|
+
'c', 'node_type',
|
232
|
+
'H8', 'hash_prefix',
|
233
|
+
'H*', 'node'
|
234
|
+
])
|
235
|
+
|
236
|
+
INNER_NODE = Bistro.new([
|
237
|
+
'H16', nil, # unused
|
238
|
+
'c', 'node_type', # can be one of NODE_TYPES for: 'account_node' or 'tx_node'
|
239
|
+
'H8', 'hp_inner_node',
|
240
|
+
'H64', 'child0',
|
241
|
+
'H64', 'child1',
|
242
|
+
'H64', 'child2',
|
243
|
+
'H64', 'child3',
|
244
|
+
'H64', 'child4',
|
245
|
+
'H64', 'child5',
|
246
|
+
'H64', 'child6',
|
247
|
+
'H64', 'child7',
|
248
|
+
'H64', 'child8',
|
249
|
+
'H64', 'child9',
|
250
|
+
'H64', 'child10',
|
251
|
+
'H64', 'child11',
|
252
|
+
'H64', 'child12',
|
253
|
+
'H64', 'child13',
|
254
|
+
'H64', 'child14',
|
255
|
+
'H64', 'child15',
|
256
|
+
'H64', 'child16',
|
257
|
+
'H64', 'child17',
|
258
|
+
'H64', 'child18',
|
259
|
+
'H64', 'child19',
|
260
|
+
'H64', 'child20',
|
261
|
+
'H64', 'child21',
|
262
|
+
'H64', 'child22',
|
263
|
+
'H64', 'child23',
|
264
|
+
'H64', 'child24',
|
265
|
+
'H64', 'child25',
|
266
|
+
'H64', 'child26',
|
267
|
+
'H64', 'child27',
|
268
|
+
'H64', 'child28',
|
269
|
+
'H64', 'child29',
|
270
|
+
'H64', 'child30',
|
271
|
+
'H64', 'child31'
|
272
|
+
])
|
273
|
+
|
274
|
+
LEDGER = Bistro.new([
|
275
|
+
'H16', nil, # unused
|
276
|
+
'c', 'nt_ledger',
|
277
|
+
'H8', 'hp_ledger_master',
|
278
|
+
'N', 'index',
|
279
|
+
'Q', 'total_coins',
|
280
|
+
'H64', 'parent_hash',
|
281
|
+
'H64', 'tx_hash',
|
282
|
+
'H64', 'account_hash',
|
283
|
+
'N', 'parent_close_time',
|
284
|
+
'N', 'close_time',
|
285
|
+
'C', 'close_time_resolution',
|
286
|
+
'C', 'close_flags',
|
287
|
+
])
|
288
|
+
|
289
|
+
CURRENCY_CODE = Bistro.new([
|
290
|
+
'C', 'type_code',
|
291
|
+
'C11', 'reserved1',
|
292
|
+
'C3', 'iso_code',
|
293
|
+
'C5', 'reserved2'
|
294
|
+
])
|
295
|
+
end # module Format
|
296
|
+
end # module NodeStore
|
297
|
+
end # module XRBP
|
data/lib/xrbp/overlay.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module XRBP
|
2
|
+
module Overlay
|
3
|
+
class Connection
|
4
|
+
attr_reader :host, :port
|
5
|
+
attr_accessor :node
|
6
|
+
|
7
|
+
def initialize(host, port)
|
8
|
+
@host = host
|
9
|
+
@port = port
|
10
|
+
@node = Crypto.node
|
11
|
+
end
|
12
|
+
|
13
|
+
def socket
|
14
|
+
@socket ||= TCPSocket.open(host, port)
|
15
|
+
end
|
16
|
+
|
17
|
+
def closed?
|
18
|
+
socket.closed?
|
19
|
+
end
|
20
|
+
|
21
|
+
def ssl_socket
|
22
|
+
@ssl_socket ||= begin
|
23
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
24
|
+
ssl_context.ssl_version = :SSLv23
|
25
|
+
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
26
|
+
|
27
|
+
_ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
28
|
+
_ssl_socket.sync_close = true
|
29
|
+
|
30
|
+
_ssl_socket
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def handshake
|
35
|
+
@handshake ||= Handshake.new self
|
36
|
+
end
|
37
|
+
|
38
|
+
###
|
39
|
+
|
40
|
+
def connect
|
41
|
+
ssl_socket.connect
|
42
|
+
handshake.execute!
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
ssl_socket.close
|
47
|
+
end
|
48
|
+
|
49
|
+
def write(data)
|
50
|
+
ssl_socket.puts(data)
|
51
|
+
end
|
52
|
+
|
53
|
+
def read
|
54
|
+
ssl_socket.gets
|
55
|
+
end
|
56
|
+
|
57
|
+
def read_frames
|
58
|
+
frame = nil
|
59
|
+
remaining = nil
|
60
|
+
while !closed?
|
61
|
+
read_sockets, _, _ = IO.select([ssl_socket], nil, nil, 0.1)
|
62
|
+
if read_sockets && read_sockets[0]
|
63
|
+
out = ssl_socket.read_nonblock(1024)
|
64
|
+
|
65
|
+
if frame.nil?
|
66
|
+
type = Frame::TYPE_INFER.decode(out)
|
67
|
+
frame = Frame.new type["type"], type["size"]
|
68
|
+
out = out[Frame::TYPE_INFER.size..-1]
|
69
|
+
end
|
70
|
+
|
71
|
+
_, remaining = frame << out
|
72
|
+
if frame.complete?
|
73
|
+
# TODO extra specific protobuf data structure
|
74
|
+
# from data, set on frame
|
75
|
+
yield frame
|
76
|
+
frame = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
# XXX: doesn't feel right to just
|
80
|
+
# discard remaining, look into this
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end # class Connection
|
85
|
+
end # module WebClient
|
86
|
+
end # module XRBP
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "bistro"
|
2
|
+
require_relative './ripple.proto'
|
3
|
+
|
4
|
+
module XRBP
|
5
|
+
module Overlay
|
6
|
+
class Frame
|
7
|
+
TYPE_INFER = Bistro.new([
|
8
|
+
'L>', 'size',
|
9
|
+
'S>', 'type'
|
10
|
+
])
|
11
|
+
|
12
|
+
def self.header_size
|
13
|
+
TYPE_INFER.size
|
14
|
+
end
|
15
|
+
|
16
|
+
def header_size
|
17
|
+
self.class.header_size
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.type_name(t)
|
21
|
+
Protocol::MessageType.lookup(t)
|
22
|
+
end
|
23
|
+
|
24
|
+
###
|
25
|
+
|
26
|
+
attr_reader :type, :size
|
27
|
+
attr_accessor :data
|
28
|
+
|
29
|
+
def initialize(type, size)
|
30
|
+
@type = type
|
31
|
+
@size = size
|
32
|
+
|
33
|
+
@data = ""
|
34
|
+
end
|
35
|
+
|
36
|
+
def type_name
|
37
|
+
@type_name ||= self.class.type_name(type)
|
38
|
+
end
|
39
|
+
|
40
|
+
def <<(data)
|
41
|
+
remaining = size - (@data.size + header_size)
|
42
|
+
@data += data[0..remaining-1]
|
43
|
+
return @data, data[remaining..-1]
|
44
|
+
end
|
45
|
+
|
46
|
+
def complete?
|
47
|
+
(@data.size + header_size) == size
|
48
|
+
end
|
49
|
+
end # class Frame
|
50
|
+
end # module WebClient
|
51
|
+
end # module XRBP
|
@@ -0,0 +1,78 @@
|
|
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
|
+
require 'base64'
|
11
|
+
require 'openssl'
|
12
|
+
|
13
|
+
module XRBP
|
14
|
+
module Overlay
|
15
|
+
class Handshake
|
16
|
+
attr_reader :connection, :response
|
17
|
+
|
18
|
+
def initialize(connection)
|
19
|
+
@connection = connection
|
20
|
+
end
|
21
|
+
|
22
|
+
def socket
|
23
|
+
connection.ssl_socket
|
24
|
+
end
|
25
|
+
|
26
|
+
def node
|
27
|
+
connection.node
|
28
|
+
end
|
29
|
+
|
30
|
+
###
|
31
|
+
|
32
|
+
def shared
|
33
|
+
@shared ||= begin
|
34
|
+
sha512 = OpenSSL::Digest::SHA512.new
|
35
|
+
sf = socket.finished
|
36
|
+
pf = socket.peer_finished
|
37
|
+
sf = sha512.digest(sf)
|
38
|
+
pf = sha512.digest(pf)
|
39
|
+
shared = sf.to_bn ^ pf.to_bn
|
40
|
+
shared = shared.bytes.reverse.pack("C*")
|
41
|
+
shared = sha512.digest(shared)[0..31]
|
42
|
+
|
43
|
+
shared = Crypto::Key.sign_digest(node, shared)
|
44
|
+
Base64.strict_encode64(shared)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def data
|
49
|
+
@data ||=
|
50
|
+
"GET / HTTP/1.1\r
|
51
|
+
User-Agent: rippled-1.1.2\r
|
52
|
+
Upgrade: RTXP/1.2, RTXP/1.3\r
|
53
|
+
Connection: Upgrade\r
|
54
|
+
Connect-As: Leaf, Peer\r
|
55
|
+
Public-Key: #{node[:node]}\r
|
56
|
+
Session-Signature: #{shared}\r
|
57
|
+
\r\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
###
|
61
|
+
|
62
|
+
def execute!
|
63
|
+
socket.puts(data)
|
64
|
+
|
65
|
+
@response = ""
|
66
|
+
until connection.closed? # || connection.force_quit?
|
67
|
+
read_sockets, _, _ = IO.select([socket], nil, nil, 0.1)
|
68
|
+
|
69
|
+
if read_sockets && read_sockets[0]
|
70
|
+
out = socket.read_nonblock(1024)
|
71
|
+
@response += out.strip
|
72
|
+
break if out[-4..-1] == "\r\n\r\n"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end # class Handshake
|
77
|
+
end # module WebClient
|
78
|
+
end # module XRBP
|