blzrb 0.1.0

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.
@@ -0,0 +1,8 @@
1
+ require "bluzelle/constants"
2
+ require "bluzelle/error"
3
+ require "bluzelle/swarm/transaction"
4
+ require "bluzelle/swarm/request"
5
+ require "bluzelle/swarm/cosmos"
6
+ require "bluzelle/swarm/client"
7
+ require "bluzelle/utils"
8
+ require "bluzelle/version"
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bluzelle
4
+ module Constants
5
+ PREFIX = 'bluzelle'
6
+ PATH = "m/44'/118'/0'/0/0"
7
+ TOKEN_NAME = 'ubnt'
8
+ TX_COMMAND = 'txs'
9
+ BROADCAST_RETRY_SECONDS = 1
10
+ BLOCK_TIME_IN_SECONDS = 5
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bluzelle
4
+ module Error
5
+ class Error < StandardError
6
+ def initialize(msg = 'Error occurred')
7
+ super(msg)
8
+ end
9
+ end
10
+
11
+ class ApiError < Error
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,442 @@
1
+ # frozen_string_literal: true
2
+ require 'bluzelle/utils'
3
+ require 'bluzelle/constants'
4
+
5
+ module Bluzelle
6
+ module Swarm
7
+ class Client
8
+ include Bluzelle::Constants
9
+ include Bluzelle::Utils
10
+
11
+ attr_reader :address, :mnemonic, :uuid, :chain_id, :endpoint, :app_service
12
+ attr_reader :cosmos
13
+
14
+ # Creates a new Bluzelle connection.
15
+
16
+ # @param options [Hash]
17
+ # @return [Bluzelle::Swarm::Client]
18
+ def initialize(options = {})
19
+ options = stringify_keys(options)
20
+
21
+ validate_string(options['mnemonic'], 'Mnemonic must be a string.')
22
+ validate_string(options['uuid'], 'UUID must be a string.')
23
+
24
+ @mnemonic = options['mnemonic']
25
+ @uuid = options['uuid']
26
+ @chain_id = options['chain_id'] || 'bluzelle'
27
+ @endpoint = options['endpoint'] || 'http://localhost:1317'
28
+ @app_service = 'crud'
29
+
30
+ @cosmos = Cosmos.new(
31
+ mnemonic: @mnemonic,
32
+ endpoint: @endpoint,
33
+ chain_id: @chain_id
34
+ )
35
+
36
+ @address = @cosmos.address
37
+ end
38
+
39
+ # Create a field in the database
40
+ #
41
+ # @param [String] key The name of the key to create
42
+ # @param [String] value The string value to set the key
43
+ # @param [Hash] gas_info Hash containing gas parameters
44
+ # @param [Hash] lease_info Minimum time for key to remain in database
45
+ #
46
+ # @return [void]
47
+ def create(key, value, gas_info, lease_info = nil)
48
+ validate_string(key, 'key must be a string')
49
+ validate_string(value, 'value must be a string')
50
+
51
+ lease = convert_lease(lease_info)
52
+
53
+ validate_lease(lease, 'invalid lease time')
54
+
55
+ @cosmos.send_transaction(
56
+ 'post',
57
+ "#{@app_service}/create",
58
+ build_params({ 'Key' => key, 'Value' => value, 'Lease' => lease }),
59
+ gas_info
60
+ )
61
+ end
62
+
63
+ # Update a field in the database
64
+ #
65
+ # @param [String] key The name of the key to update
66
+ # @param [String] value The string value to set the key
67
+ # @param [Hash] gas_info Hash containing gas parameters
68
+ # @param [Hash] lease_info Minimum time for key to remain in database
69
+ #
70
+ # @return [void]
71
+ def update(key, value, gas_info, lease_info = nil)
72
+ validate_string(key, 'Key must be a string')
73
+ validate_string(value, 'Value must be a string')
74
+
75
+ lease = convert_lease(lease_info)
76
+
77
+ validate_lease(lease, 'invalid lease time')
78
+
79
+ @cosmos.send_transaction(
80
+ 'post',
81
+ "#{@app_service}/update",
82
+ build_params({ Key: key, Value: value, Lease: lease }),
83
+ gas_info
84
+ )
85
+ end
86
+
87
+ # Retrieve the value of a key without consensus verification
88
+ #
89
+ # @param [String] key The key to retrieve
90
+ # @param [Boolean] prove
91
+ #
92
+ # @return [String] String value of the key
93
+ def read(key, prove = false)
94
+ validate_string(key, 'Key must be a string')
95
+
96
+ path = prove ? 'pread' : 'read'
97
+ url = "#{@app_service}/#{path}/#{@uuid}/#{key}"
98
+
99
+ @cosmos.query(url)
100
+ .dig('result', 'value')
101
+ end
102
+
103
+ # Retrieve the value of a key via a transaction (i.e uses consensus)
104
+ #
105
+ # @param [String] key The key to retrieve
106
+ # @param [Hash] gas_info Hash containing gas parameters
107
+ #
108
+ # @return [String] String value of the key
109
+ def tx_read(key, gas_info)
110
+ validate_string(key, 'Key must be a string')
111
+
112
+ @cosmos.send_transaction(
113
+ 'post',
114
+ "#{@app_service}/read",
115
+ build_params({ Key: key }),
116
+ gas_info
117
+ ).dig('value')
118
+ end
119
+
120
+ # Delete a field from the database
121
+ #
122
+ # @param [String] key The name of the key to delete
123
+ # @param [Hash] gas_info Hash containing gas parameters
124
+ #
125
+ # @return [void]
126
+ def delete(key, gas_info)
127
+ validate_string(key, 'Key must be a string')
128
+
129
+ @cosmos.send_transaction(
130
+ 'delete',
131
+ "#{@app_service}/delete",
132
+ build_params({ Key: key }),
133
+ gas_info
134
+ )
135
+ end
136
+
137
+ # Query to see if a key is in the database. This function bypasses
138
+ # the consensus and cryptography mechanisms in favour of speed.
139
+ #
140
+ # @param [String] key The name of the key to query
141
+ #
142
+ # @return [Boolean]
143
+ def has(key)
144
+ validate_string(key, 'Key must be a string')
145
+
146
+ @cosmos.query("#{@app_service}/has/#{@uuid}/#{key}")
147
+ .dig('result', 'has')
148
+ end
149
+
150
+ # Query to see if a key is in the database via a transaction (i.e uses consensus)
151
+ #
152
+ # @param [String] key The name of the key to query
153
+ # @param [Hash] gas_info Hash containing gas parameters
154
+ #
155
+ # @return [Boolean]
156
+ def tx_has(key, gas_info)
157
+ validate_string(key, 'Key must be a string')
158
+
159
+ @cosmos.send_transaction(
160
+ 'post',
161
+ "#{@app_service}/has",
162
+ build_params({ Key: key }),
163
+ gas_info
164
+ ).dig('has')
165
+ end
166
+
167
+ # Retrieve a list of all keys. This function bypasses the consensus
168
+ # and cryptography mechanisms in favour of speed.
169
+ #
170
+ # @return [Array]
171
+ def keys
172
+ @cosmos.query("#{@app_service}/keys/#{@uuid}")
173
+ .dig('result', 'keys') || []
174
+ end
175
+
176
+ # Retrieve a list of all keys via a transaction (i.e use consensus)
177
+ #
178
+ # @param [Hash] gas_info Hash containing gas parameters
179
+ #
180
+ # @return [Array]
181
+ def tx_keys(gas_info)
182
+ @cosmos.send_transaction(
183
+ 'post',
184
+ "#{@app_service}/keys",
185
+ build_params({}),
186
+ gas_info
187
+ ).dig('keys') || []
188
+ end
189
+
190
+ # Change the name of an existing key
191
+ #
192
+ # @param [String] key
193
+ # @param [String] new_key
194
+ # @param [Hash] gas_info Hash containing gas parameters
195
+ #
196
+ # @return [void]
197
+ def rename(key, new_key, gas_info)
198
+ validate_string(key, 'key must be a string')
199
+ validate_string(new_key, 'new_key must be a string')
200
+
201
+ @cosmos.send_transaction(
202
+ 'post',
203
+ "#{@app_service}/rename",
204
+ build_params({ Key: key, NewKey: new_key }),
205
+ gas_info
206
+ )
207
+ end
208
+
209
+ # Retrieve the number of keys in the current database/uuid.
210
+ # This function bypasses the consensus and cryptography
211
+ # mechanisms in favor of speed
212
+ #
213
+ # @return [Integer]
214
+ def count
215
+ @cosmos.query("#{app_service}/count/#{@uuid}")
216
+ .dig('result', 'count')
217
+ end
218
+
219
+ # Retrieve the number of keys in the current database/uuid via a transaction
220
+ #
221
+ # @param [Hash] gas_info Hash containing gas parameters
222
+ #
223
+ # @return [Integer]
224
+ def tx_count(gas_info)
225
+ @cosmos.send_transaction(
226
+ 'post',
227
+ "#{@app_service}/count",
228
+ build_params({}),
229
+ gas_info
230
+ ).dig('count')
231
+ end
232
+
233
+ # Remove all keys in the current database/uuid
234
+ #
235
+ # @param [Hash] gas_info Hash containing gas parameters
236
+ #
237
+ # @return [void]
238
+ def delete_all(gas_info)
239
+ @cosmos.send_transaction(
240
+ 'post',
241
+ "#{@app_service}/deleteall",
242
+ build_params({}),
243
+ gas_info
244
+ )
245
+ end
246
+
247
+ # Enumerate all keys and values in the current database/uuid.
248
+ # This function bypasses the consensus and cryptography mechanisms in favor of speed
249
+ #
250
+ # @return [Array]
251
+ def key_values
252
+ @cosmos.query("#{app_service}/keyvalues/#{@uuid}")
253
+ .dig('result', 'keyvalues') || []
254
+ end
255
+
256
+ # Enumerate all keys and values in the current database/uuid via a transaction
257
+ #
258
+ # @param [Hash] gas_info Hash containing gas parameters
259
+ #
260
+ # @return [Array]
261
+ def tx_key_values(gas_info)
262
+ @cosmos.send_transaction(
263
+ 'post',
264
+ "#{@app_service}/keyvalues",
265
+ build_params({}),
266
+ gas_info
267
+ ).dig('keyvalues') || []
268
+ end
269
+
270
+ # Update multiple fields in the database
271
+ #
272
+ # @param [Array]
273
+ # @param [Hash] gas_info Hash containing gas parameters
274
+ def multi_update(key_values, gas_info)
275
+ validate_array(key_values, 'key_values must be an array')
276
+
277
+ key_values.each do |key_value|
278
+ validate_string(key_value.dig('key'), 'All keys must be strings')
279
+ validate_string(key_value.dig('value'), 'All values must be string')
280
+ end
281
+
282
+ @cosmos.send_transaction(
283
+ 'post',
284
+ "#{@app_service}/multiupdate",
285
+ build_params({ KeyValues: key_values }),
286
+ gas_info
287
+ )
288
+ end
289
+
290
+ # Retrieve the minimum time remaining on the lease for a key.
291
+ # This function bypasses the consensus and cryptography mechanisms in favor of speed
292
+ #
293
+ # @param [String] key
294
+ #
295
+ # @return [String]
296
+ def get_lease(key)
297
+ validate_string(key, 'key must be a string')
298
+
299
+ @cosmos.query("#{@app_service}/getlease/#{@uuid}/#{key}")
300
+ .dig('result', 'lease').to_i * BLOCK_TIME_IN_SECONDS
301
+ end
302
+
303
+ # Retrieve the minimum time remaining on the lease for a key, using a transaction
304
+ #
305
+ # @param [String] key The key to retrieve the lease information for
306
+ # @param [Hash] gas_info Hash containing gas parameters
307
+ #
308
+ # @return [String]
309
+ def tx_get_lease(key, gas_info)
310
+ validate_string(key, 'key must be a string')
311
+
312
+ @cosmos.send_transaction(
313
+ 'post',
314
+ "#{@app_service}/getlease",
315
+ build_params({ Key: key }),
316
+ gas_info
317
+ ).dig('lease').to_i * BLOCK_TIME_IN_SECONDS
318
+ end
319
+
320
+ # Update the minimum time remaining on the lease for a key
321
+ #
322
+ # @param [String] key The key to retrieve the lease information for
323
+ # @param [Hash] gas_info Hash containing gas parameters
324
+ # @param [Hash] lease Minimum time for key to remain in database
325
+ def renew_lease(key, lease, gas_info)
326
+ validate_string(key, 'key must be a string')
327
+
328
+ lease = convert_lease(lease)
329
+
330
+ validate_lease(lease, 'invalid lease time')
331
+
332
+ @cosmos.send_transaction(
333
+ 'post',
334
+ "#{@app_service}/renewlease",
335
+ build_params({ Key: key, Lease: lease }),
336
+ gas_info
337
+ )
338
+ end
339
+
340
+ # Update the minimum time remaining on the lease for all keys
341
+ #
342
+ # @param [Hash] gas_info Hash containing gas parameters
343
+ # @param [Hash] lease Minimum time for key to remain in database
344
+ def renew_lease_all(lease, gas_info)
345
+ lease = convert_lease(lease)
346
+
347
+ validate_lease(lease, 'invalid lease time')
348
+
349
+ @cosmos.send_transaction(
350
+ 'post',
351
+ "#{@app_service}/renewleaseall",
352
+ build_params({ Lease: lease }),
353
+ gas_info
354
+ )
355
+ end
356
+
357
+ # Retrieve a list of the n keys in the database with the shortest leases.
358
+ # This function bypasses the consensus and cryptography mechanisms in favor of speed
359
+ #
360
+ # @param [Integer] n The number of keys to retrieve the lease information for
361
+ #
362
+ # @return [Array]
363
+ def get_n_shortest_leases(n)
364
+ validate_lease(n, 'invalid value specified')
365
+
366
+ @cosmos.query("#{@app_service}/getnshortestleases/#{@uuid}/#{n}")
367
+ .dig('result', 'keyleases')
368
+ .map do |key_lease|
369
+ {
370
+ 'key' => key_lease['key'],
371
+ 'lease' => key_lease['lease'].to_i * BLOCK_TIME_IN_SECONDS
372
+ }
373
+ end
374
+ end
375
+
376
+ # Retrieve a list of the N keys/values in the database with the shortest leases,
377
+ # using a transaction
378
+ #
379
+ # @param [Integer] n The number of keys to retrieve the lease information for
380
+ # @param [Hash] gas_info Hash containing lize(options = {})gas parameters
381
+ #
382
+ # @return [Array]
383
+ def tx_get_n_shortest_leases(n, gas_info)
384
+ validate_lease(n, 'invalid value specified')
385
+
386
+ @cosmos.send_transaction(
387
+ 'post',
388
+ "#{@app_service}/getnshortestleases",
389
+ build_params({ N: n.to_s }),
390
+ gas_info
391
+ ).dig('keyleases')
392
+ .map do |key_lease|
393
+ {
394
+ 'key' => key_lease['key'],
395
+ 'lease' => key_lease['lease'].to_i * BLOCK_TIME_IN_SECONDS
396
+ }
397
+ end
398
+ end
399
+
400
+ # Retrieve information about the currently active Bluzelle account
401
+ #
402
+ # @return [Hash]
403
+ def account
404
+ @cosmos.query("auth/accounts/#{@address}")
405
+ .dig('result', 'value')
406
+ end
407
+
408
+ # Retrieve the version of the Bluzelle service
409
+ #
410
+ # @return [String]
411
+ def version
412
+ @cosmos.query('node_info')
413
+ .dig('application_version', 'version')
414
+ end
415
+
416
+ private
417
+
418
+ def validate_array(arg, msg)
419
+ raise ArgumentError, msg unless arg.is_a?(Array)
420
+ end
421
+
422
+ def validate_string(arg, msg)
423
+ raise ArgumentError, msg unless arg.is_a?(String)
424
+ end
425
+
426
+ def validate_lease(arg, msg)
427
+ raise ArgumentError, msg if arg.is_a?(Integer) && arg.negative?
428
+ end
429
+
430
+ def build_params(params)
431
+ {
432
+ 'BaseReq' => {
433
+ 'chain_id' => @chain_id,
434
+ 'from' => @address
435
+ },
436
+ 'Owner' => @address,
437
+ 'UUID' => @uuid
438
+ }.merge(params)
439
+ end
440
+ end
441
+ end
442
+ end