vchain_client 1.0.1 → 1.0.6
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/lib/vchain_client/bitcoind_blockchain_adapter.rb +175 -3
- data/lib/vchain_client/blockchain_adapter.rb +4 -0
- data/lib/vchain_client/blockchain_adapter_factory.rb +2 -1
- data/lib/vchain_client/blockchain_connection.rb +123 -3
- data/lib/vchain_client/blockcypher_blockchain_adapter.rb +152 -3
- data/lib/vchain_client/blockstack_client.rb +398 -43
- data/lib/vchain_client/signatures.rb +401 -14
- data/lib/vchain_client.rb +874 -58
- metadata +24 -3
@@ -6,102 +6,408 @@ module VChainClient
|
|
6
6
|
Xet0UYuBrILjHB9HcxFc+WwuCflIRWtRDsNfaY6Ra7j/cRYLeiocYA=="
|
7
7
|
|
8
8
|
@config = nil
|
9
|
+
@log = nil
|
9
10
|
|
10
11
|
@@recs_cache = {}
|
11
12
|
@@keys_cache = {}
|
12
13
|
|
13
14
|
def initialize(config)
|
14
15
|
@config = config
|
16
|
+
|
17
|
+
@log = Log4r::Logger["vchain_client"]
|
15
18
|
end
|
16
19
|
|
17
20
|
def checkFederativeServer(federative_server_id)
|
18
|
-
|
21
|
+
|
22
|
+
if @log.debug?
|
23
|
+
@log.debug("[Blockstack.checkFederativeServer] input:")
|
24
|
+
@log.debug("-> federative_server_id: #{federative_server_id}")
|
25
|
+
end
|
26
|
+
|
27
|
+
begin
|
28
|
+
|
29
|
+
return self.checkBlockstackRecord(federative_server_id, 'federative_server')
|
30
|
+
|
31
|
+
rescue => e
|
32
|
+
|
33
|
+
if @log.error?
|
34
|
+
@log.error("[Blockstack.checkFederativeServer] checkBlockstackRecord raised exception:")
|
35
|
+
@log.error("#{e.class}, #{e.message}")
|
36
|
+
@log.error("-> federative_server_id: #{federative_server_id}")
|
37
|
+
@log.error("--> federative_server_id: #{federative_server_id}")
|
38
|
+
@log.error("--> type: federative_server")
|
39
|
+
end
|
40
|
+
|
41
|
+
raise e
|
42
|
+
end
|
19
43
|
end
|
20
44
|
|
21
45
|
def checkVerificator(verificator_id)
|
22
|
-
|
46
|
+
|
47
|
+
if @log.debug?
|
48
|
+
@log.debug("[Blockstack.checkVerificator] input:")
|
49
|
+
@log.debug("-> verificator_id: #{verificator_id}")
|
50
|
+
end
|
51
|
+
|
52
|
+
begin
|
53
|
+
|
54
|
+
return self.checkBlockstackRecord(verificator_id, 'verificator')
|
55
|
+
|
56
|
+
rescue => e
|
57
|
+
|
58
|
+
if @log.error?
|
59
|
+
@log.error("[Blockstack.checkVerificator] checkBlockstackRecord raised exception:")
|
60
|
+
@log.error("#{e.class}, #{e.message}")
|
61
|
+
@log.error("-> verificator_id: #{verificator_id}")
|
62
|
+
@log.error("--> verificator_id: #{verificator_id}")
|
63
|
+
@log.error("--> type: verificator")
|
64
|
+
end
|
65
|
+
|
66
|
+
raise e
|
67
|
+
end
|
23
68
|
end
|
24
69
|
|
25
70
|
def checkValidator(validator_id)
|
26
|
-
|
71
|
+
|
72
|
+
if @log.debug?
|
73
|
+
@log.debug("[Blockstack.checkValidator] input:")
|
74
|
+
@log.debug("-> validator_id: #{validator_id}")
|
75
|
+
end
|
76
|
+
|
77
|
+
begin
|
78
|
+
|
79
|
+
return self.checkBlockstackRecord(validator_id, 'validator')
|
80
|
+
|
81
|
+
rescue => e
|
82
|
+
|
83
|
+
if @log.error?
|
84
|
+
@log.error("[Blockstack.checkValidator] checkBlockstackRecord raised exception:")
|
85
|
+
@log.error("#{e.class}, #{e.message}")
|
86
|
+
@log.error("-> validator_id: #{validator_id}")
|
87
|
+
@log.error("--> validator_id: #{validator_id}")
|
88
|
+
@log.error("--> type: validator")
|
89
|
+
end
|
90
|
+
|
91
|
+
raise e
|
92
|
+
end
|
27
93
|
end
|
28
94
|
|
29
95
|
def checkBlockstackRecord(blockstack_id, type)
|
30
96
|
|
31
|
-
|
97
|
+
if @log.debug?
|
98
|
+
@log.debug("[Blockstack.checkBlockstackRecord] input:")
|
99
|
+
@log.debug("-> blockstack_id: #{blockstack_id}")
|
100
|
+
@log.debug("-> type: #{type}")
|
101
|
+
end
|
102
|
+
|
103
|
+
record = nil
|
104
|
+
|
105
|
+
begin
|
106
|
+
|
107
|
+
record = self.getBlockstackRecord(blockstack_id)
|
108
|
+
|
109
|
+
rescue => e
|
110
|
+
|
111
|
+
if @log.error?
|
112
|
+
@log.error("[Blockstack.checkBlockstackRecord] getBlockstackRecord raised exception:")
|
113
|
+
@log.error("#{e.class}, #{e.message}")
|
114
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
115
|
+
@log.error("-> type: #{type}")
|
116
|
+
@log.error("--> blockstack_id: #{blockstack_id}")
|
117
|
+
end
|
118
|
+
|
119
|
+
raise e
|
120
|
+
end
|
121
|
+
|
122
|
+
if record == nil
|
123
|
+
if @log.error?
|
124
|
+
@log.error("[Blockstack.checkBlockstackRecord] failed to retrieve record")
|
125
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
126
|
+
@log.error("-> type: #{type}")
|
127
|
+
@log.error("--> blockstack_id: #{blockstack_id}")
|
128
|
+
end
|
129
|
+
|
130
|
+
return false
|
131
|
+
end
|
32
132
|
|
33
133
|
signaturesHelper = VChainClient::Signatures.new(@config)
|
34
134
|
|
135
|
+
if @log.debug?
|
136
|
+
@log.debug("[Blockstack.checkBlockstackRecord] Signatures initialized")
|
137
|
+
end
|
138
|
+
|
35
139
|
if record != nil
|
140
|
+
|
36
141
|
if record.key?("pubkey")
|
142
|
+
|
37
143
|
if record.key?("vchain_role")
|
38
144
|
|
39
145
|
if record["vchain_role"] != type
|
40
|
-
|
146
|
+
if @log.error?
|
147
|
+
@log.error("[Blockstack.checkBlockstackRecord] type mismatch")
|
148
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
149
|
+
@log.error("-> type: #{type}")
|
150
|
+
@log.error("--> '"+ record["vchain_role"] +"'")
|
151
|
+
end
|
152
|
+
|
153
|
+
return false
|
154
|
+
end
|
155
|
+
|
156
|
+
if !record.key?("validator_blockstack_id")
|
157
|
+
if @log.error?
|
158
|
+
@log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'validator_blockstack_id' field")
|
159
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
160
|
+
@log.error("-> type: #{type}")
|
161
|
+
end
|
162
|
+
|
163
|
+
return false
|
41
164
|
end
|
42
165
|
|
43
166
|
validator_blockstack_id = record["validator_blockstack_id"]
|
44
|
-
if validator_blockstack_id != nil
|
45
167
|
|
46
|
-
|
168
|
+
if @log.debug?
|
169
|
+
@log.debug("[Blockstack.checkBlockstackRecord] record's vchain_role is '"+ record["vchain_role"] +"'")
|
170
|
+
end
|
171
|
+
|
172
|
+
if record["vchain_role"] != 'validator'
|
173
|
+
|
174
|
+
if @log.debug?
|
175
|
+
@log.debug("[Blockstack.checkBlockstackRecord] going to check validator for #{blockstack_id}, validator_id: #{validator_blockstack_id}")
|
176
|
+
end
|
177
|
+
|
178
|
+
begin
|
179
|
+
|
47
180
|
if !self.checkValidator(validator_blockstack_id)
|
48
|
-
|
181
|
+
|
182
|
+
if @log.error?
|
183
|
+
@log.error("[Blockstack.checkBlockstackRecord] failed to check validator")
|
184
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
185
|
+
@log.error("-> type: #{type}")
|
186
|
+
@log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
|
187
|
+
end
|
188
|
+
|
189
|
+
return false
|
49
190
|
end
|
50
|
-
end
|
51
191
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
192
|
+
rescue => e
|
193
|
+
if @log.error?
|
194
|
+
@log.error("[Blockstack.checkBlockstackRecord] checkValidator raised exception:")
|
195
|
+
@log.error("#{e.class}, #{e.message}")
|
196
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
197
|
+
@log.error("-> type: #{type}")
|
198
|
+
@log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
|
199
|
+
end
|
200
|
+
|
201
|
+
raise e
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
validator_pub_key = nil
|
207
|
+
if record["vchain_role"] != 'validator'
|
208
|
+
|
209
|
+
begin
|
210
|
+
|
211
|
+
validator_pub_key = self.getPublicKey(validator_blockstack_id)
|
212
|
+
|
213
|
+
rescue => e
|
214
|
+
if @log.error?
|
215
|
+
@log.error("[Blockstack.checkBlockstackRecord] getPublicKey raised exception:")
|
216
|
+
@log.error("#{e.class}, #{e.message}")
|
217
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
218
|
+
@log.error("-> type: #{type}")
|
219
|
+
@log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
|
220
|
+
end
|
221
|
+
|
222
|
+
raise e
|
223
|
+
end
|
224
|
+
|
225
|
+
else
|
226
|
+
validator_pub_key = MASTER_PUBLIC_KEY;
|
227
|
+
end
|
58
228
|
|
59
|
-
|
229
|
+
if validator_pub_key == nil
|
230
|
+
if @log.error?
|
231
|
+
@log.error("[Blockstack.checkBlockstackRecord] failed to retrieve public key:")
|
232
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
233
|
+
@log.error("-> type: #{type}")
|
234
|
+
@log.error("--> validator_blockstack_id: #{validator_blockstack_id}")
|
235
|
+
end
|
60
236
|
|
61
|
-
|
237
|
+
return false
|
238
|
+
end
|
239
|
+
|
240
|
+
# check client's sig
|
241
|
+
client_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["pubkey"] + record["sig_version"];
|
242
|
+
|
243
|
+
begin
|
62
244
|
|
63
245
|
if signaturesHelper.verifySignature(client_sig_to_check, record["client_sig"], record["pubkey"])
|
246
|
+
|
64
247
|
# check validator's sig
|
65
248
|
validator_sig_to_check = record["vchain_id"] + record["vchain_role"] + blockstack_id + record["pubkey"] + record["sig_version"] + record["validator_vchain_id"] + validator_blockstack_id
|
66
249
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
250
|
+
begin
|
251
|
+
|
252
|
+
if signaturesHelper.verifySignature(validator_sig_to_check, record["validator_sig"], validator_pub_key)
|
253
|
+
|
254
|
+
return true;
|
255
|
+
|
256
|
+
else
|
257
|
+
if @log.error?
|
258
|
+
@log.error("[Blockstack.checkBlockstackRecord] failed to verify validator_sig")
|
259
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
260
|
+
@log.error("-> type: #{type}")
|
261
|
+
@log.error("--> validator_sig_to_check: #{validator_sig_to_check}")
|
262
|
+
@log.error("--> validator_sig: "+ Base64.encode64(record["validator_sig"]))
|
263
|
+
@log.error("--> validator_pub_key: "+ record["validator_pub_key"])
|
264
|
+
end
|
265
|
+
|
266
|
+
return false
|
267
|
+
end
|
268
|
+
|
269
|
+
rescue => e
|
270
|
+
if @log.error?
|
271
|
+
@log.error("[Blockstack.checkBlockstackRecord] verifySignature for validator_sig raised exception:")
|
272
|
+
@log.error("#{e.class}, #{e.message}")
|
273
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
274
|
+
@log.error("-> type: #{type}")
|
275
|
+
@log.error("--> validator_sig_to_check: #{validator_sig_to_check}")
|
276
|
+
@log.error("--> validator_sig: "+ Base64.encode64(record["validator_sig"]))
|
277
|
+
@log.error("--> validator_pub_key: "+ record["validator_pub_key"])
|
278
|
+
end
|
279
|
+
|
280
|
+
raise e
|
72
281
|
end
|
73
282
|
|
74
283
|
else
|
75
|
-
|
284
|
+
if @log.error?
|
285
|
+
@log.error("[Blockstack.checkBlockstackRecord] failed to verify client_sig")
|
286
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
287
|
+
@log.error("-> type: #{type}")
|
288
|
+
@log.error("--> client_sig_to_check: #{client_sig_to_check}")
|
289
|
+
@log.error("--> client_sig: "+ Base64.encode64(record["client_sig"]))
|
290
|
+
@log.error("--> pubkey: "+ record["pubkey"])
|
291
|
+
end
|
292
|
+
|
293
|
+
return false
|
76
294
|
end
|
77
|
-
|
295
|
+
|
296
|
+
rescue => e
|
297
|
+
if @log.error?
|
298
|
+
@log.error("[Blockstack.checkBlockstackRecord] verifySignature for client_sig raised exception:")
|
299
|
+
@log.error("#{e.class}, #{e.message}")
|
300
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
301
|
+
@log.error("-> type: #{type}")
|
302
|
+
@log.error("--> client_sig_to_check: #{client_sig_to_check}")
|
303
|
+
@log.error("--> client_sig: "+ Base64.encode64(record["client_sig"]))
|
304
|
+
@log.error("--> pubkey: "+ record["pubkey"])
|
305
|
+
end
|
306
|
+
|
307
|
+
raise e
|
308
|
+
end
|
309
|
+
|
310
|
+
else
|
311
|
+
if @log.error?
|
312
|
+
@log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'vchain_role' field")
|
313
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
314
|
+
@log.error("-> type: #{type}")
|
315
|
+
end
|
78
316
|
end
|
317
|
+
|
318
|
+
else
|
319
|
+
if @log.error?
|
320
|
+
@log.error("[Blockstack.checkBlockstackRecord] record doesn't have 'pubkey' field")
|
321
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
322
|
+
@log.error("-> type: #{type}")
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
else
|
327
|
+
if @log.error?
|
328
|
+
@log.error("[Blockstack.checkBlockstackRecord] record is null")
|
329
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
330
|
+
@log.error("-> type: #{type}")
|
79
331
|
end
|
80
332
|
end
|
81
333
|
|
82
|
-
return
|
334
|
+
return false
|
83
335
|
end
|
84
336
|
|
85
337
|
def getPublicKey(blockstack_id)
|
338
|
+
|
339
|
+
if @log.debug?
|
340
|
+
@log.debug("[Blockstack.getPublicKey] input:")
|
341
|
+
@log.debug("-> blockstack_id: #{blockstack_id}")
|
342
|
+
end
|
343
|
+
|
86
344
|
if @@keys_cache.key?(blockstack_id)
|
345
|
+
|
346
|
+
if @log.debug?
|
347
|
+
@log.debug("[Blockstack.getPublicKey] '#{blockstack_id}' is in a cache")
|
348
|
+
end
|
349
|
+
|
87
350
|
return @@keys_cache[blockstack_id]
|
88
351
|
end
|
89
352
|
|
90
|
-
|
91
|
-
|
92
|
-
|
353
|
+
if @log.debug?
|
354
|
+
@log.debug("[Blockstack.getPublicKey] '#{blockstack_id}' is not in a cache yet")
|
355
|
+
end
|
93
356
|
|
94
|
-
|
357
|
+
begin
|
95
358
|
|
96
|
-
|
97
|
-
|
98
|
-
|
359
|
+
record = self.getBlockstackRecord(blockstack_id);
|
360
|
+
|
361
|
+
if record != nil
|
362
|
+
|
363
|
+
if record.key?("pubkey")
|
364
|
+
|
365
|
+
@@keys_cache[blockstack_id] = record["pubkey"]
|
366
|
+
|
367
|
+
return record["pubkey"]
|
368
|
+
|
369
|
+
else
|
370
|
+
if @log.error?
|
371
|
+
@log.error("[Blockstack.getPublicKey] record '#{blockstack_id}' doesn't have 'pubkey' field")
|
372
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
373
|
+
@log.error("--> blockstack_id: #{blockstack_id}")
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
else
|
378
|
+
if @log.error?
|
379
|
+
@log.error("[Blockstack.getPublicKey] failed to retrieve '#{blockstack_id}' record")
|
380
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
381
|
+
@log.error("--> blockstack_id: #{blockstack_id}")
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
rescue => e
|
386
|
+
if @log.error?
|
387
|
+
@log.error("[Blockstack.getPublicKey] getBlockstackRecord raised exception:")
|
388
|
+
@log.error("#{e.class}, #{e.message}")
|
389
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
390
|
+
@log.error("--> blockstack_id: #{blockstack_id}")
|
391
|
+
end
|
392
|
+
|
393
|
+
raise e
|
394
|
+
end
|
99
395
|
|
100
396
|
return nil
|
101
397
|
end
|
102
398
|
|
103
399
|
def getBlockstackRecord(blockstack_id)
|
400
|
+
|
401
|
+
if @log.debug?
|
402
|
+
@log.debug("[Blockstack.getBlockstackRecord] input:")
|
403
|
+
@log.debug("-> blockstack_id: #{blockstack_id}")
|
404
|
+
end
|
405
|
+
|
104
406
|
if @@recs_cache.key?(blockstack_id)
|
407
|
+
if @log.debug?
|
408
|
+
@log.debug("[Blockstack.getBlockstackRecord] '#{blockstack_id}' is in a cache")
|
409
|
+
end
|
410
|
+
|
105
411
|
return @@recs_cache[blockstack_id]
|
106
412
|
end
|
107
413
|
|
@@ -109,24 +415,61 @@ module VChainClient
|
|
109
415
|
|
110
416
|
cmd = blockstack_path +" get_name_zonefile "+ blockstack_id
|
111
417
|
|
112
|
-
|
113
|
-
|
418
|
+
if @log.debug?
|
419
|
+
@log.debug("[Blockstack.getBlockstackRecord] using '#{blockstack_path}' as a Blockstack path")
|
420
|
+
@log.debug("[Blockstack.getBlockstackRecord] running '#{cmd}'")
|
421
|
+
end
|
422
|
+
|
423
|
+
ret = nil
|
424
|
+
|
425
|
+
begin
|
426
|
+
|
427
|
+
ret = `#{cmd}`
|
428
|
+
|
429
|
+
rescue => e
|
430
|
+
if @log.error?
|
431
|
+
@log.error("[Blockstack.getBlockstackRecord] cmd call '#{cmd}' raised exception:")
|
432
|
+
@log.error("#{e.class}, #{e.message}")
|
433
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
434
|
+
@log.error("--> '#{cmd}'")
|
435
|
+
end
|
436
|
+
|
437
|
+
raise e
|
438
|
+
end
|
439
|
+
|
440
|
+
if ret == nil
|
441
|
+
if @log.error?
|
442
|
+
@log.error("[Blockstack.getBlockstackRecord] failed to retrieve record from cmd call")
|
443
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
444
|
+
@log.error("--> '#{cmd}'")
|
445
|
+
end
|
446
|
+
|
114
447
|
return nil
|
115
448
|
end
|
449
|
+
|
450
|
+
if @log.debug?
|
451
|
+
@log.debug("[Blockstack.getBlockstackRecord] cmd call return:")
|
452
|
+
@log.debug(ret)
|
453
|
+
end
|
454
|
+
|
116
455
|
ret = JSON.parse ret
|
117
456
|
|
118
457
|
fz = {}
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
458
|
+
if ret.key?("txt")
|
459
|
+
ret["txt"].each { |rec|
|
460
|
+
if rec.key?("name") && rec.key?("txt")
|
461
|
+
fz[rec["name"]] = rec["txt"]
|
462
|
+
end
|
463
|
+
}
|
464
|
+
end
|
465
|
+
|
466
|
+
if @log.debug?
|
467
|
+
@log.debug("[Blockstack.getBlockstackRecord] fz:")
|
468
|
+
@log.debug(fz)
|
127
469
|
end
|
128
470
|
|
129
|
-
if fz.key?("A1")
|
471
|
+
if fz.key?("A1") && fz.key?("A2") && fz.key?("A3") && fz.key?("A4") && fz.key?("A5") && fz.key?("A6") && fz.key?("A7") && fz.key?("A8")
|
472
|
+
|
130
473
|
pubkey_aligned = fz["A1"]
|
131
474
|
pubkey = pubkey_aligned[0..63] +"\n"+ pubkey_aligned[64..pubkey_aligned.length]
|
132
475
|
|
@@ -141,10 +484,22 @@ module VChainClient
|
|
141
484
|
"client_sig" => Base64.decode64(fz["A8"])
|
142
485
|
}
|
143
486
|
|
487
|
+
if @log.debug?
|
488
|
+
@log.debug("[Blockstack.getBlockstackRecord] output:")
|
489
|
+
@log.debug(output)
|
490
|
+
end
|
491
|
+
|
144
492
|
@@recs_cache[blockstack_id] = output
|
145
493
|
@@keys_cache[blockstack_id] = pubkey
|
146
494
|
|
147
495
|
return output
|
496
|
+
|
497
|
+
else
|
498
|
+
if @log.error?
|
499
|
+
@log.error("[Blockstack.getBlockstackRecord] no 'A*' field")
|
500
|
+
@log.error("-> blockstack_id: #{blockstack_id}")
|
501
|
+
@log.error("--> blockstack_id: #{blockstack_id}")
|
502
|
+
end
|
148
503
|
end
|
149
504
|
|
150
505
|
return nil
|