vchain_client 1.0.15 → 1.0.16

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
  SHA1:
3
- metadata.gz: f7cee1ed6c6a5984dc6a2895676e516a9ec6eeaa
4
- data.tar.gz: e6579fd0ab9f8d7460f7d46dd98f6b9625ba675a
3
+ metadata.gz: d4d647625f6cb2ba6bd8783a3da98bd8a0845cb6
4
+ data.tar.gz: dcf9699f8907e8a5fdb3cfe73f62ef9f8a50a439
5
5
  SHA512:
6
- metadata.gz: e94a3dd3e7327a2b007bf75588366ee8cbdd103f8f32cb356e1c6e31bb3e31d7c21f6391e27770919117df1fc46e95c5bc8facc99b875fd0dd7b6b34707c1f40
7
- data.tar.gz: 2532de0a43e0de96ec538d27d1f13912fd0c33bb06aee3292789c765da8f8897cb8ad12cc51a8ecf2f74836b7f393a380899a4a97f73d480b73a496c9d47fd93
6
+ metadata.gz: 4ff4a4f2ebeccf0d056eaa9b8aae892716d179b19e3c28c793c1da5f9dbad4741abdd3923fbcb1afdcb0d93ca6b29675fdb3d4ae648c545f7ef51fd0c0e3d932
7
+ data.tar.gz: ca812c1e1f01704802606a27a7b8cf2e6996f8cacc4f9de9b86a442b41a5284cd716cffa2fb6958c8ace666bd43659df6e2f1445609e8468ae0e2c521d07a921
data/lib/vchain_client.rb CHANGED
@@ -15,7 +15,11 @@ module VChainClient
15
15
  require 'vchain_client/signatures'
16
16
  require 'vchain_client/blockstack_client'
17
17
 
18
- FIELD_TYPE_HASHED = "fbb6889f44061c2a91e17a411cf168f9457981257a5e0a31fb706cd5cd1e64c263780a42a1fd858ee69429869ab2e2c53b9d94c4a26946f2b0c12f8ce2812d6b"
18
+ FIELD_TYPE_TRAVEL_DOCUMENT = "travel_document"
19
+ FIELD_TYPE_TEST_DOCUMENT = "test_document"
20
+
21
+ FIELD_TYPE_TRAVEL_DOCUMENT_HASHED = "fbb6889f44061c2a91e17a411cf168f9457981257a5e0a31fb706cd5cd1e64c263780a42a1fd858ee69429869ab2e2c53b9d94c4a26946f2b0c12f8ce2812d6b"
22
+ FIELD_TYPE_TEST_DOCUMENT_HASHED = "e061cf61078d74025ab1d136e0a78785097b8ef721107e940cac1ca836ed5fa6af907344b761447274ce0558d95d4126e94e11f04eb70c3885afcc96f9cfe985"
19
23
 
20
24
  @config = nil
21
25
  @log = nil
@@ -32,23 +36,94 @@ module VChainClient
32
36
  }
33
37
  end
34
38
 
39
+ def full_hash(arr)
40
+ output = {}
41
+
42
+ arr.each { |k, v|
43
+ if k != "doc_hash"
44
+ output[Digest::SHA512.hexdigest(k)] = Digest::SHA512.hexdigest(v)
45
+ else
46
+ output[k] = Digest::SHA512.hexdigest(v)
47
+ end
48
+ }
49
+
50
+ return output
51
+ end
52
+
35
53
  def cut(arr)
36
54
  arr.each { |k, v|
37
- if k == "type" || k == "citizenship" || k == "first_name" || k == "last_name" || k == "birthdate" || k == "number" || k == "sex"
38
-
39
- arr[k] = v
40
-
41
- else
55
+ if arr["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
56
+ if k == "type" || k == "citizenship" || k == "first_name" || k == "last_name" || k == "birthdate" || k == "number" || k == "sex"
57
+ arr[k] = v
58
+ else
59
+ arr.delete(k)
60
+ end
42
61
 
43
- arr.delete(k)
62
+ elsif arr["type"] == FIELD_TYPE_TEST_DOCUMENT_HASHED
63
+ if k == "type" || k == "a" || k == "b" || k == "c" || k == "d" || k == "e"
64
+ arr[k] = v
65
+ else
66
+ arr.delete(k)
67
+ end
44
68
 
45
69
  end
46
70
  }
47
71
  end
48
72
 
73
+ def get_doc_hash(arr)
74
+ if arr["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
75
+
76
+ what_to_hash = arr["type"] + arr["citizenship"] + arr["number"] + arr["first_name"] + arr["last_name"] + arr["birthdate"] + arr["sex"]
77
+
78
+ return Digest::SHA512.hexdigest(what_to_hash)
79
+
80
+ elsif arr["type"] == FIELD_TYPE_TEST_DOCUMENT_HASHED
81
+
82
+ what_to_hash = arr["type"] + arr["a"] + arr["b"] + arr["c"] + arr["d"] + arr["e"]
83
+
84
+ return Digest::SHA512.hexdigest(what_to_hash)
85
+
86
+ end
87
+ end
88
+
49
89
  def get_credentials_fields(type)
50
- if type == FIELD_TYPE_HASHED
90
+ if type == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
51
91
  return ["type", "citizenship", "number", "first_name", "last_name", "birthdate"]
92
+
93
+ elsif type == FIELD_TYPE_TEST_DOCUMENT_HASHED
94
+ return ["type", "a", "b", "c"]
95
+
96
+ end
97
+
98
+ if @log.error?
99
+ @log.error("[get_credentials_fields] unknown document type: '"+ type +"'")
100
+ end
101
+
102
+ return nil
103
+ end
104
+
105
+ def get_similar_credential_sets(type)
106
+ if type == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
107
+ output = []
108
+ output.push(["type", "last_name", "birthdate", "number", "citizenship"])
109
+ output.push(["type", "first_name", "birthdate", "number", "citizenship"])
110
+ output.push(["type", "first_name", "last_name", "birthdate", "number"])
111
+ output.push(["type", "first_name", "last_name", "birthdate", "citizenship"])
112
+ output.push(["type", "first_name", "last_name", "number", "citizenship"])
113
+ output.push(["type", "last_name", "number", "citizenship"])
114
+ output.push(["type", "first_name", "number", "citizenship"])
115
+ output.push(["type", "birthdate", "number", "citizenship"])
116
+ output.push(["type", "first_name", "last_name", "birthdate"])
117
+ output.push(["type", "number", "citizenship"])
118
+ return output
119
+
120
+ elsif type == FIELD_TYPE_TEST_DOCUMENT_HASHED
121
+ output = []
122
+ output.push(["type", "a", "b"])
123
+ output.push(["type", "a", "c"])
124
+ output.push(["type", "b", "c"])
125
+ return output
126
+
52
127
  end
53
128
 
54
129
  if @log.error?
@@ -59,10 +134,16 @@ module VChainClient
59
134
  end
60
135
 
61
136
  def get_credentials_hash(document)
62
- if document["type"] == FIELD_TYPE_HASHED
137
+ if document["type"] == FIELD_TYPE_TRAVEL_DOCUMENT_HASHED
63
138
  what_to_hash = document["type"] + document["citizenship"] + document["number"] + document["first_name"] + document["last_name"] + document["birthdate"]
64
139
 
65
140
  return Digest::SHA512.hexdigest(what_to_hash)
141
+
142
+ elsif document["type"] == FIELD_TYPE_TEST_DOCUMENT_HASHED
143
+ what_to_hash = document["type"] + document["a"] + document["b"] + document["c"]
144
+
145
+ return Digest::SHA512.hexdigest(what_to_hash)
146
+
66
147
  end
67
148
 
68
149
  if @log.error?
@@ -112,83 +193,36 @@ module VChainClient
112
193
  return previous_parent
113
194
  end
114
195
 
115
- def do_use(input, ignore_possible_matches = false)
116
-
117
- client_id = @config["client_id"]
118
- api_url = @config["api"]["url"] + "v0.1/use/";
119
-
120
- document = input
121
- document = self.cut(document)
122
- document = self.hash(document)
196
+ def add_data_point(point_type, input, weight)
123
197
 
124
- if @log.debug?
125
- @log.debug("[use] will call "+ api_url +" using vchain_client_id "+ client_id)
126
- @log.debug("[use] hashed input:")
127
- @log.debug(document)
128
- end
129
-
130
- document["client_id"] = client_id
131
- document["ignore_possible_matches"] = ignore_possible_matches
132
-
133
- if @log.debug?
134
- @log.debug("[use] send_data:")
135
- @log.debug(document)
136
- end
137
-
138
- begin
139
-
140
- req = RestClient.post(api_url,
141
- document.to_json,
142
- {'Content-Type' => 'application/json'})
198
+ client_id = @config["client_id"]
199
+ api_url = @config["api"]["url"] + "v0.1/addDataPoint/"
143
200
 
144
- if req.code != 200
201
+ time = Time.now.getutc
202
+ timestamp = time.to_i
145
203
 
146
- if @log.error?
147
- @log.error("[use] response with code "+ req.code.to_s)
148
- @log.error("-> ignore_possible_matches: #{ignore_possible_matches}")
149
- @log.error("-> client_id: #{client_id}")
150
- @log.error("-> api_url: #{api_url}")
151
- @log.error("-> document:")
152
- @log.error(document)
153
- end
204
+ document = input
205
+
206
+ document = self.hash(document)
207
+
208
+ document = self.cut(document)
154
209
 
155
- return false
210
+ doc_hash = self.get_doc_hash(document)
156
211
 
157
- end
212
+ if weight > 1
213
+
214
+ weight = 1
158
215
 
159
- return true
216
+ elsif weight < 0
160
217
 
161
- rescue => e
162
- if @log.error?
163
- @log.error("[use] RestClient.post raised exception")
164
- @log.error("#{e.class}, #{e.message}")
165
- @log.error("-> ignore_possible_matches: #{ignore_possible_matches}")
166
- @log.error("-> client_id: #{client_id}")
167
- @log.error("-> api_url: #{api_url}")
168
- @log.error("-> document:")
169
- @log.error(document)
170
- end
218
+ weight = 0
171
219
 
172
- raise e
173
220
  end
174
221
 
175
- end
176
-
177
- def do_verify(verification_type, input)
178
-
179
- client_id = @config["client_id"]
180
- api_url = @config["api"]["url"] + "v0.1/verify/"
181
-
182
- time = Time.now.getutc
183
- timestamp = time.to_i
184
-
185
- document = input
186
- document = self.cut(document)
187
- document = self.hash(document)
188
-
189
222
  if @log.debug?
190
223
  @log.debug("[verify] will call "+ api_url +" using vchain_client_id "+ client_id)
191
- @log.debug("-> verification_type: "+ verification_type)
224
+ @log.debug("-> point_type: "+ point_type)
225
+ @log.debug("-> weight: "+ weight.to_s)
192
226
  @log.debug("-> timestamp: "+ timestamp.to_s)
193
227
  @log.debug("-> hashed input:")
194
228
  @log.debug(document)
@@ -196,17 +230,18 @@ module VChainClient
196
230
 
197
231
  signaturesHelper = VChainClient::Signatures.new(@config)
198
232
 
199
- verifications_data = nil
233
+ point_signatures = nil
200
234
 
201
235
  begin
202
236
 
203
- verifications_data = signaturesHelper.signVerification(verification_type, document, timestamp)
237
+ point_signatures = signaturesHelper.signDataPoint(point_type, document, doc_hash, weight, timestamp)
204
238
 
205
239
  rescue => e
206
240
  if @log.error?
207
241
  @log.error("[verify] Signatures.signVerification raised exception")
208
242
  @log.error("#{e.class}, #{e.message}")
209
- @log.error("-> verification_type: "+ verification_type)
243
+ @log.error("-> point_type: "+ point_type)
244
+ @log.error("-> weight: "+ weight.to_s)
210
245
  @log.error("-> timestamp: "+ timestamp.to_s)
211
246
  @log.error("-> client_id: #{client_id}")
212
247
  @log.error("-> api_url: #{api_url}")
@@ -217,10 +252,11 @@ module VChainClient
217
252
  raise e
218
253
  end
219
254
 
220
- if verifications_data == nil
255
+ if point_signatures == nil
221
256
  if @log.error?
222
257
  @log.error("[verify] failed to Signatures.signVerification")
223
- @log.error("-> verification_type: "+ verification_type)
258
+ @log.error("-> point_type: "+ point_type)
259
+ @log.error("-> weight: "+ weight.to_s)
224
260
  @log.error("-> timestamp: "+ timestamp.to_s)
225
261
  @log.error("-> client_id: #{client_id}")
226
262
  @log.error("-> api_url: #{api_url}")
@@ -232,8 +268,8 @@ module VChainClient
232
268
  end
233
269
 
234
270
  if @log.debug?
235
- @log.debug("[verify] verifications_data:")
236
- @log.debug(document)
271
+ @log.debug("[verify] point_signatures:")
272
+ @log.debug(point_signatures)
237
273
  end
238
274
 
239
275
  document = Hash[document.sort]
@@ -247,14 +283,15 @@ module VChainClient
247
283
 
248
284
  begin
249
285
 
250
- whole_signature = signaturesHelper.signRequest(document, timestamp)
286
+ whole_signature = signaturesHelper.signRequest(document, point_type, weight, timestamp)
251
287
 
252
288
  rescue => e
253
289
 
254
290
  if @log.error?
255
291
  @log.error("[verify] Signatures.signRequest raised exception:")
256
292
  @log.error("#{e.class}: #{e.message}")
257
- @log.error("-> verification_type: #{verification_type}")
293
+ @log.error("-> point_type: #{point_type}")
294
+ @log.error("-> weight: "+ weight.to_s)
258
295
  @log.error("-> timestamp: "+ timestamp.to_s)
259
296
  @log.error("-> client_id: #{client_id}")
260
297
  @log.error("-> api_url: #{api_url}")
@@ -270,7 +307,8 @@ module VChainClient
270
307
 
271
308
  if @log.error?
272
309
  @log.error("[verify] failed to sign request")
273
- @log.error("-> verification_type: #{verification_type}")
310
+ @log.error("-> point_type: #{point_type}")
311
+ @log.error("-> weight: "+ weight.to_s)
274
312
  @log.error("-> timestamp: "+ timestamp.to_s)
275
313
  @log.error("-> client_id: #{client_id}")
276
314
  @log.error("-> api_url: #{api_url}")
@@ -291,9 +329,10 @@ module VChainClient
291
329
  send_data = {}
292
330
  send_data["client_id"] = client_id
293
331
  send_data["data"] = document
332
+ send_data["weight"] = weight.to_s
294
333
  send_data["timestamp"] = timestamp.to_s
295
- send_data["verification_type"] = verification_type;
296
- send_data["verifications_signatures"] = verifications_data
334
+ send_data["type"] = point_type;
335
+ send_data["point_signatures"] = point_signatures
297
336
  send_data["signature"] = whole_signature
298
337
 
299
338
  if @log.debug?
@@ -312,7 +351,8 @@ module VChainClient
312
351
  @log.error("[verify] response with code "+ req.code.to_s)
313
352
  @log.error("-> client_id: #{client_id}")
314
353
  @log.error("-> api_url: #{api_url}")
315
- @log.error("-> verification_type: #{verification_type}")
354
+ @log.error("-> point_type: #{point_type}")
355
+ @log.error("-> weight: "+ weight.to_s)
316
356
  @log.error("-> timestamp: "+ timestamp.to_s)
317
357
  @log.error("-> send_data:")
318
358
  @log.error(send_data)
@@ -334,7 +374,8 @@ module VChainClient
334
374
  @log.error("#{e.class}, #{e.message}")
335
375
  @log.error("-> client_id: #{client_id}")
336
376
  @log.error("-> api_url: #{api_url}")
337
- @log.error("-> verification_type: #{verification_type}")
377
+ @log.error("-> point_type: #{point_type}")
378
+ @log.error("-> weight: "+ weight.to_s)
338
379
  @log.error("-> timestamp: "+ timestamp.to_s)
339
380
  @log.error("-> send_data:")
340
381
  @log.error(send_data)
@@ -344,19 +385,22 @@ module VChainClient
344
385
  end
345
386
  end
346
387
 
347
- def do_check(input, is_already_hashed=false)
388
+ def check(input, is_already_hashed=false)
348
389
 
349
390
  client_id = @config["client_id"]
391
+
350
392
  api_url = @config["api"]["url"] + "v0.1/check/";
351
393
 
352
394
  document = input
353
395
 
354
- document = self.cut(document)
355
-
356
396
  if (!is_already_hashed)
357
- document = self.hash(document)
397
+ document = self.hash(document)
358
398
  end
359
399
 
400
+ document = self.cut(document)
401
+
402
+ sent_document = document.clone
403
+
360
404
  document["client_id"] = client_id
361
405
 
362
406
  if @log.debug?
@@ -380,7 +424,7 @@ module VChainClient
380
424
  @log.error("[check] response with code "+ req.code.to_s)
381
425
  @log.error("-> client_id: #{client_id}")
382
426
  @log.error("-> api_url: #{api_url}")
383
- @log.debug("-> is_already_hashed: #{is_already_hashed}")
427
+ @log.error("-> is_already_hashed: #{is_already_hashed}")
384
428
  @log.error("-> sent data:")
385
429
  @log.error(document)
386
430
  end
@@ -395,7 +439,7 @@ module VChainClient
395
439
  @log.error("#{e.class}, #{e.message}")
396
440
  @log.error("-> client_id: #{client_id}")
397
441
  @log.error("-> api_url: #{api_url}")
398
- @log.debug("-> is_already_hashed: #{is_already_hashed}")
442
+ @log.error("-> is_already_hashed: #{is_already_hashed}")
399
443
  @log.error("-> sent data:")
400
444
  @log.error(document)
401
445
  end
@@ -403,800 +447,823 @@ module VChainClient
403
447
  raise e
404
448
  end
405
449
 
450
+ res = JSON.parse req.body
451
+
406
452
  if @log.debug?
407
- @log.debug("[check] response code is 200:")
453
+ @log.debug("response:")
408
454
  @log.debug(req.body)
409
455
  end
410
456
 
411
- res = JSON.parse req.body
457
+ if res["status"].downcase == "error"
412
458
 
413
- validated_verifications = {}
414
-
415
- if res.key?("document")
459
+ return {
460
+ "status" => "error",
461
+ "reason" => res["error_reason_code"]
462
+ }
416
463
 
417
- res_document = res["document"]
464
+ else
418
465
 
419
- if @log.debug?
420
- @log.debug("[check] recieved verifications")
421
- end
466
+ # success result
422
467
 
423
- credentials_document = document
468
+ res_docs_index = {}
424
469
 
425
- if res["status"] == "ERROR" || res["status"] == "error"
426
- if res["error_reason_code"] == "DOCUMENT_POSSIBLE_MISTAKES"
427
- credentials_document = {}
470
+ res["docs"].each { |res_doc|
428
471
 
429
- credentials_fields = self.get_credentials_fields(document["type"])
472
+ res_doc_credentials_hash = self.get_credentials_hash(res_doc)
430
473
 
431
- credentials_fields.each_with_index{ |field,index|
432
- if document[field] != res_document["values"][field]
433
- credentials_document[field] = res_document["values"][field]
434
- else
435
- credentials_document[field] = document[field]
436
- end
437
- }
474
+ if !res_docs_index.key?(res_doc_credentials_hash)
475
+ res_docs_index[res_doc_credentials_hash] = []
438
476
  end
439
- end
440
477
 
441
- credentials_hash = self.get_credentials_hash(credentials_document)
478
+ res_docs_index[res_doc_credentials_hash].push(res_doc)
479
+ }
480
+
481
+ validated_data_points = self.validate_data_points(res["data_points"], res["docs"])
482
+
483
+ if validated_data_points.length == 0
484
+
485
+ # not found
486
+
487
+ result = {}
488
+
489
+ sent_document.each { |field, value|
490
+ result[field] = 0
491
+ }
492
+
493
+ return {
494
+ "status" => "success",
495
+ "validated" => result
496
+ }
442
497
 
443
- if @log.debug?
444
- @log.debug("[check] credentials_hash: "+ credentials_hash)
445
498
  end
446
499
 
447
- blockchainConnection = VChainClient::BlockchainConnection.new(@config)
500
+ # analyse
448
501
 
449
- blockstackClient = VChainClient::BlockstackClient.new(@config)
502
+ sent_doc_hash = self.get_doc_hash(sent_document)
450
503
 
451
- signaturesHelper = VChainClient::Signatures.new(@config)
504
+ sent_credentials_hash = self.get_credentials_hash(sent_document)
452
505
 
453
- res_document.each { |field, v|
454
- if v.key?("verifications") && v["verifications"].length > 0 && field != "type"
455
-
456
- if @log.debug?
457
- @log.debug("[check] check recieved verifications for '"+ field +"', number of recieved verifications: "+ v["verifications"].length.to_s)
458
- end
506
+ hashed_sent_doc = self.full_hash(sent_document)
459
507
 
460
- v["verifications"].each { |verification|
508
+ hashed_sent_doc_hash = Digest::SHA512.hexdigest(sent_doc_hash)
461
509
 
462
- if @log.debug?
463
- @log.debug("[check] field '"+ field +"', verification:")
464
- @log.debug(verification)
465
- end
510
+ # trying to find exact match by doc_hash
466
511
 
467
- if !verification.key?("blockchain_reciepts")
468
- if @log.error?
469
- @log.error("[check] not a valid verification - no blockchain_reciepts key")
470
- @log.error(verification)
471
- @log.error(document)
472
- end
512
+ if validated_data_points.key?(hashed_sent_doc_hash)
513
+
514
+ # exact match found by doc_hash
473
515
 
474
- next
475
- end
516
+ result = {}
476
517
 
477
- if verification["blockchain_reciepts"].length <= 0
478
- if @log.error?
479
- @log.error("[check] not a valid verification - blockchain_reciepts is empty")
480
- @log.error("field '"+ field +"'")
481
- @log.error(verification)
482
- @log.error(document)
483
- end
518
+ exact_match = validated_data_points[hashed_sent_doc_hash]
484
519
 
485
- next
486
- end
520
+ sent_document.each { |field, value|
521
+
522
+ hashed_field = Digest::SHA512.hexdigest(field)
487
523
 
488
- # 1a. check credentials_hash
489
- if credentials_hash != verification["credentials_hash"]
490
- if @log.error?
491
- @log.error("[check] not a valid verification - credentials_hash mismatch ("+ credentials_hash +")")
492
- @log.error("field '"+ field +"'")
493
- @log.error(verification)
494
- @log.error(document)
495
- end
524
+ if exact_match.key?(hashed_field)
496
525
 
497
- next
498
- end
526
+ result[field] = exact_match[hashed_field]
499
527
 
500
- # 1b. check field_hash
501
- field_hash = Digest::SHA512.hexdigest(field)
502
- if field_hash != verification["field_hash"]
503
- if @log.error?
504
- @log.error("[check] not a valid verification - field_hash mismatch ("+ field_hash +")")
505
- @log.error("field '"+ field +"'")
506
- @log.error(verification)
507
- @log.error(document)
508
- end
528
+ else
509
529
 
510
- next
511
- end
530
+ result[field] = 0
512
531
 
513
- # 1c. check data_hash
514
- data_hash = Digest::SHA512.hexdigest(document[field])
515
- if res.key?("document")
516
- if res["document"].key?("values")
517
- if res["document"]["values"].key?(field)
518
- if res["document"]["values"][field] != document[field]
519
- data_hash = Digest::SHA512.hexdigest(res["document"]["values"][field])
520
- end
521
- end
522
- end
523
- end
524
- if data_hash != verification["data_hash"]
525
- if @log.error?
526
- @log.error("[check] not a valid verification - data_hash mismatch ("+ data_hash +")")
527
- @log.error("field '"+ field +"'")
528
- @log.error(verification)
529
- @log.error(document)
530
- end
532
+ end
531
533
 
532
- next
533
- end
534
+ }
534
535
 
535
- # 1d. check checksum
536
- checksum_to_hash = credentials_hash + field_hash + data_hash
537
- checksum = Digest::SHA512.hexdigest(checksum_to_hash)
538
- if checksum != verification["checksum"]
539
- if @log.error?
540
- @log.error("[check] not a valid verification - checksum mismatch ("+ checksum +")")
541
- @log.error("field '"+ field +"'")
542
- @log.error(verification)
543
- @log.error(document)
544
- @log.error(credentials_hash)
545
- @log.error(field_hash)
546
- @log.error(data_hash)
547
- end
536
+ return {
537
+ "status" => "success",
538
+ "validated" => result
539
+ }
548
540
 
549
- next
550
- end
541
+ else
551
542
 
552
- verification_hash = verification["verification_hash"]
553
- if @log.debug?
554
- @log.debug("[check] verification_hash: "+ verification_hash)
555
- end
543
+ # search by credentials_hash
544
+
545
+ found_docs = []
546
+ if res_docs_index.key?(sent_credentials_hash)
547
+ found_docs = res_docs_index[sent_credentials_hash]
548
+ end
556
549
 
557
- # 2. check verification_hash to be in target_proof's
558
- # first element
559
- reciepts_validated = 0
560
- verification["blockchain_reciepts"].each { |reciept|
550
+ if found_docs.length > 0
561
551
 
562
- if @log.debug?
563
- @log.debug("reciept to check:")
564
- @log.debug(reciept)
565
- end
552
+ # matches found by credentials
566
553
 
567
- if !reciept.key?("target_proof")
568
- if @log.error?
569
- @log.error("[check] not a valid blockchain reciept - no target_proof")
570
- @log.error(reciept)
571
- @log.error("field '"+ field +"'")
572
- @log.error(verification)
573
- @log.error(document)
574
- end
554
+ result = {}
575
555
 
576
- break
577
- end
556
+ possible_mistakes = []
578
557
 
579
- if reciept["target_proof"].length <= 0
580
- if @log.error?
581
- @log.error("[check] not a valid blockchain reciept - target_proof length is <= 0")
582
- @log.error(reciept)
583
- @log.error("field '"+ field +"'")
584
- @log.error(verification)
585
- @log.error(document)
586
- end
558
+ cred_fields = self.get_credentials_fields(sent_document["type"]);
587
559
 
588
- break
589
- end
560
+ non_cred_fields_index = {}
590
561
 
591
- if reciept["target_proof"][0]["left"] != verification_hash && reciept["target_proof"][0]["right"] != verification_hash
592
- if @log.error?
593
- @log.error("[check] not a valid blockchain reciept - no target element in target_proof.0")
594
- @log.error(reciept)
595
- @log.error("field '"+ field +"'")
596
- @log.error(verification)
597
- @log.error(document)
598
- end
562
+ found_docs.each { |cred_doc|
599
563
 
600
- break
564
+ cred_doc_hash = self.get_doc_hash(cred_doc)
565
+ cred_doc_hash = Digest::SHA512.hexdigest(cred_doc_hash)
566
+
567
+ cred_doc_exact_match = validated_data_points[cred_doc_hash]
568
+
569
+ # fill credential fields
570
+ cred_fields.each { |cred_field|
571
+
572
+ cred_field_hashed = Digest::SHA512.hexdigest(cred_field)
573
+
574
+ if !result.key?(cred_field)
575
+ result[cred_field] = 0
601
576
  end
602
577
 
603
- # verification_hash is in tree
604
- # and in right position
605
- # now,
606
-
607
- # 3. check tree convergence to root hash
608
- # and compare this computed root hash
609
- # with merkle_tree_root_hash from response
610
- if @log.debug?
611
- @log.debug("will now build merkle tree with")
612
- @log.debug(reciept["target_proof"])
613
- @log.debug(reciept["timestamp"])
578
+ if cred_doc_exact_match.key?(cred_field_hashed)
579
+ result[cred_field] += cred_doc_exact_match[cred_field_hashed]
614
580
  end
615
581
 
616
- computed_tree_root_hash = self.build_merkle_tree(reciept["target_proof"], reciept["timestamp"])
582
+ }
583
+
584
+ # fill non credential fields
585
+ cred_doc.each { |field, value|
617
586
 
618
- if @log.debug?
619
- @log.debug("computed tree root hash = "+ computed_tree_root_hash)
620
- end
587
+ if !cred_fields.include?(field) && field != "doc_hash"
621
588
 
622
- if computed_tree_root_hash == nil
623
- if @log.error?
624
- @log.error("[check] not a valid blockchain reciept - failed to compute tree root hash")
625
- @log.error(reciept)
626
- @log.error("field '"+ field +"'")
627
- @log.error(verification)
628
- @log.error(document)
589
+ non_cred_field_hashed = Digest::SHA512.hexdigest(field)
590
+
591
+ if !non_cred_fields_index.key?(field)
592
+ non_cred_fields_index[field] = {}
629
593
  end
630
594
 
631
- break
632
- end
633
- if computed_tree_root_hash != reciept["merkle_tree_root_hash"]
634
- if @log.error?
635
- @log.error("[check] not a valid blockchain reciept - merkle tree root hash mismatch ("+ computed_tree_root_hash +", "+ reciept["merkle_tree_root_hash"] +")")
636
- @log.error(reciept)
637
- @log.error("field '"+ field +"'")
638
- @log.error(verification)
639
- @log.error(document)
595
+ if !non_cred_fields_index[field].key?(value)
596
+ non_cred_fields_index[field][value] = 0
640
597
  end
641
598
 
642
- break
643
- end
644
-
645
- last_proof_index = reciept["target_proof"].length - 1
646
- reciept_stored_last_parent = reciept["target_proof"][last_proof_index]["parent"]
647
- if reciept_stored_last_parent != computed_tree_root_hash
648
- if @log.error?
649
- @log.error("[check] not a valid blockchain reciept - last stored parent != computed_tree_root_hash ("+ reciept_stored_last_parent +", "+ computed_tree_root_hash +")")
650
- @log.error(reciept)
651
- @log.error("field '"+ field +"'")
652
- @log.error(verification)
653
- @log.error(document)
599
+ if cred_doc_exact_match.key?(non_cred_field_hashed)
600
+ non_cred_fields_index[field][value] += cred_doc_exact_match[non_cred_field_hashed]
654
601
  end
655
602
 
656
- break
657
603
  end
658
604
 
659
- # 4. check OP_RETURN in Bitcoin's tx,
660
- # compare it to computed root hash of a tree
661
- # retrieve some info from tx to verify signature
662
- tx = nil
663
-
664
- begin
665
-
666
- tx = blockchainConnection.getTx(reciept["blockchain_txid"])
667
-
668
- rescue => e
669
- if @log.error?
670
- @log.error("[check] BlockchainConnection.getTx raised exception:")
671
- @log.error("#{e.class}, #{e.message}")
672
- @log.error("-> client_id: #{client_id}")
673
- @log.error("-> api_url: #{api_url}")
674
- @log.error("-> is_already_hashed: #{is_already_hashed}")
675
- @log.error("-> sent data:")
676
- @log.error(document)
677
- @log.error("--> blockchain_txid: "+ reciept["blockchain_txid"])
678
- end
605
+ }
679
606
 
680
- raise e
681
- end
607
+ }
682
608
 
609
+ non_cred_fields_index.each { |field, values|
683
610
 
684
- if @log.debug?
685
- @log.debug("[check] tx ["+ reciept["blockchain_txid"] +"]:")
686
- @log.debug(tx)
687
- end
611
+ if values.length == 1
688
612
 
689
- if tx == nil
690
- if @log.error?
691
- @log.error("[check] not a valid blockchain reciept - failed to retrieve TX from Blockchain")
692
- @log.error(reciept)
693
- @log.error("field '"+ field +"'")
694
- @log.error(verification)
695
- @log.error(document)
613
+ values.take(1).each { |value, validated_count|
614
+ if value == sent_document[field]
615
+ result[field] = validated_count
616
+ else
617
+ possible_mistakes.push(field)
696
618
  end
619
+ }
697
620
 
698
- break
699
- end
621
+ else
622
+ possible_mistakes.push(field)
623
+ end
700
624
 
701
- if tx["block_hash"] != reciept["blockchain_block_hash"]
702
- if @log.error?
703
- @log.error("[check] not a valid blockchain reciept - block_hash mismatch")
704
- @log.error(tx)
705
- @log.error(reciept)
706
- @log.error("field '"+ field +"'")
707
- @log.error(verification)
708
- @log.error(document)
709
- end
625
+ }
710
626
 
711
- break
712
- end
627
+ return {
628
+ "status" => "success",
629
+ "possible_mistakes" => possible_mistakes,
630
+ "validated" => result
631
+ }
713
632
 
714
- if tx["block_timestamp"] != reciept["blockchain_timestamp"]
715
- if @log.error?
716
- @log.error("[check] not a valid blockchain reciept - timestamp mismatch")
717
- @log.error(tx)
718
- @log.error(reciept)
719
- @log.error("field '"+ field +"'")
720
- @log.error(verification)
721
- @log.error(document)
722
- end
633
+ else
723
634
 
724
- break
725
- end
635
+ # search for possible errors in credentials
726
636
 
727
- if tx["op_return"] != computed_tree_root_hash
728
- if @log.error?
729
- @log.error("[check] not a valid blockchain reciept - op_return mismatch")
730
- @log.error(computed_tree_root_hash)
731
- @log.error(tx)
732
- @log.error(reciept)
733
- @log.error("field '"+ field +"'")
734
- @log.error(verification)
735
- @log.error(document)
736
- end
637
+ similar_sets = self.get_similar_credential_sets(sent_document["type"])
737
638
 
738
- break
739
- end
639
+ result = {}
640
+ possible_mistakes = []
740
641
 
741
- blockchain_txid = reciept["blockchain_txid"];
742
- blockchain_block_hash = tx["block_hash"];
743
- blockchain_timestamp = tx["block_timestamp"];
744
-
745
- if @log.debug?
746
- @log.debug(blockchain_txid)
747
- @log.debug(blockchain_block_hash)
748
- @log.debug(blockchain_timestamp)
749
- end
642
+ other_fields_index = {}
750
643
 
751
- # 5. check tree signature:
752
- # a) federative server record in Blockstack (recursive)
753
- # b) tree_signature
754
-
755
- # a) federative server record in Blockstack (recursive)
756
- begin
757
-
758
- if !blockstackClient.checkFederativeServer(reciept["federative_server_id"])
759
- if @log.error?
760
- @log.error("[check] not a valid blockchain reciept - failed to check federative server")
761
- @log.error("-> client_id: #{client_id}")
762
- @log.error("-> api_url: #{api_url}")
763
- @log.error("-> is_already_hashed: #{is_already_hashed}")
764
- @log.error("-> sent data:")
765
- @log.error(document)
766
- @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
767
- end
644
+ similar_sets.each { |lookup_set|
768
645
 
769
- break
770
- end
646
+ lookup_set_match_found = false
771
647
 
772
- rescue => e
773
- if @log.error?
774
- @log.error("[check] Blockstack.checkFederativeServer raised exception:")
775
- @log.error("#{e.class}, #{e.message}")
776
- @log.error("-> client_id: #{client_id}")
777
- @log.error("-> api_url: #{api_url}")
778
- @log.error("-> is_already_hashed: #{is_already_hashed}")
779
- @log.error("-> sent data:")
780
- @log.error(document)
781
- @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
782
- end
648
+ res["docs"].each { |res_doc|
783
649
 
784
- raise e
785
- end
650
+ is_matching = true
786
651
 
787
- # b) check tree signature
788
- federative_server_pubkey = nil
652
+ lookup_set.each { |lookup_field|
653
+ sent_doc_val = sent_document[lookup_field]
654
+ res_doc_val = res_doc[lookup_field]
789
655
 
790
- begin
791
-
792
- federative_server_pubkey = blockstackClient.getPublicKey(reciept["federative_server_id"])
793
-
794
- rescue => e
795
- if @log.error?
796
- @log.error("[check] Blockstack.getPublicKey raised exception:")
797
- @log.error("#{e.class}, #{e.message}")
798
- @log.error("-> client_id: #{client_id}")
799
- @log.error("-> api_url: #{api_url}")
800
- @log.error("-> is_already_hashed: #{is_already_hashed}")
801
- @log.error("-> sent data:")
802
- @log.error(document)
803
- @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
656
+ if sent_doc_val != res_doc_val
657
+ is_matching = false
658
+ break
804
659
  end
660
+ }
805
661
 
806
- raise e
807
- end
662
+ if is_matching
663
+ matching_doc_hash = self.get_doc_hash(res_doc)
664
+ matching_doc_hash = Digest::SHA512.hexdigest(matching_doc_hash)
808
665
 
809
- if federative_server_pubkey == nil
810
- if @log.error?
811
- @log.error("[check] not a valid blockchain reciept - failed to retrieve public key for federative server '"+ reciept["federative_server_id"] +"'")
812
- @log.error("-> client_id: #{client_id}")
813
- @log.error("-> api_url: #{api_url}")
814
- @log.error("-> is_already_hashed: #{is_already_hashed}")
815
- @log.error("-> sent data:")
816
- @log.error(document)
817
- @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
818
- end
666
+ matching_exact_match = validated_data_points[matching_doc_hash]
819
667
 
820
- break
821
- end
822
-
823
- if @log.debug?
824
- @log.debug("federative server pubkey:")
825
- @log.debug(federative_server_pubkey)
826
- end
668
+ lookup_set.each { |lookup_field|
827
669
 
828
- begin
829
-
830
- if !signaturesHelper.checkTreeSignature(computed_tree_root_hash, blockchain_txid, blockchain_block_hash, blockchain_timestamp, reciept["federative_server_id"], reciept["federative_server_version"], Base64.decode64(reciept["tree_signature"]), federative_server_pubkey)
831
- if @log.error?
832
- @log.error("[check] not a valid blockchain reciept - failed to verify tree signature")
833
- @log.error("-> client_id: #{client_id}")
834
- @log.error("-> api_url: #{api_url}")
835
- @log.debug("-> is_already_hashed: #{is_already_hashed}")
836
- @log.error("-> sent data:")
837
- @log.error(document)
838
- @log.error("--> computed_tree_root_hash: #{computed_tree_root_hash}")
839
- @log.error("--> blockchain_txid: #{blockchain_txid}")
840
- @log.error("--> blockchain_block_hash: #{blockchain_block_hash}")
841
- @log.error("--> blockchain_timestamp: #{blockchain_timestamp}")
842
- @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
843
- @log.error("--> federative_server_version: "+ reciept["federative_server_version"])
844
- @log.error("--> tree_signature: "+ Base64.decode64(reciept["tree_signature"]))
845
- @log.error("--> federative_server_pubkey: #{federative_server_pubkey}")
846
- end
670
+ lookup_field_hashed = Digest::SHA512.hexdigest(lookup_field)
847
671
 
848
- break
849
- end
672
+ result[lookup_field] = matching_exact_match[lookup_field_hashed]
673
+ }
850
674
 
851
- rescue => e
852
- if @log.error?
853
- @log.error("[check] Blockstack.checkTreeSignature raised exception:")
854
- @log.error("#{e.class}, #{e.message}")
855
- @log.error("-> client_id: #{client_id}")
856
- @log.error("-> api_url: #{api_url}")
857
- @log.debug("-> is_already_hashed: #{is_already_hashed}")
858
- @log.error("-> sent data:")
859
- @log.error(document)
860
- @log.error("--> computed_tree_root_hash: #{computed_tree_root_hash}")
861
- @log.error("--> blockchain_txid: #{blockchain_txid}")
862
- @log.error("--> blockchain_block_hash: #{blockchain_block_hash}")
863
- @log.error("--> blockchain_timestamp: #{blockchain_timestamp}")
864
- @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
865
- @log.error("--> federative_server_version: "+ reciept["federative_server_version"])
866
- @log.error("--> tree_signature: "+ Base64.decode64(reciept["tree_signature"]))
867
- @log.error("--> federative_server_pubkey: #{federative_server_pubkey}")
868
- end
675
+ res_doc.each { |field, value|
676
+
677
+ if !lookup_set.include?(field) && field != "doc_hash"
869
678
 
870
- raise e
871
- end
679
+ other_field_hashed = Digest::SHA512.hexdigest(field)
680
+
681
+ if !other_fields_index.key?(field)
682
+ other_fields_index[field] = {}
683
+ end
872
684
 
873
- reciepts_validated += 1
874
- }
685
+ if !other_fields_index[field].key?(value)
686
+ other_fields_index[field][value] = 0
687
+ end
875
688
 
876
- if reciepts_validated != verification["blockchain_reciepts"].length
877
- if @log.error?
878
- @log.error("[check] not a valid verification - not every reciept were validated")
879
- @log.error("field '"+ field +"'")
880
- @log.error(verification)
881
- @log.error(document)
882
- end
689
+ if matching_exact_match.key?(other_field_hashed)
690
+ other_fields_index[field][value] += matching_exact_match[other_field_hashed]
691
+ end
883
692
 
884
- next
885
- end
693
+ end
886
694
 
887
- # 6. check verification signatures:
888
- # a) check verificator record in Blockstack (recursive)
889
- # b) check validator record in Blockstack (recursive)
890
- # c) verificator_sig
891
- # d) validtor_sig
892
-
893
- # a) check verificator record in Blockstack (recursive)
894
- begin
895
-
896
- if !blockstackClient.checkVerificator(verification["verificator_id"])
897
- if @log.error?
898
- @log.error("[check] not a valid verification - failed to check verificator record")
899
- @log.error("-> client_id: #{client_id}")
900
- @log.error("-> api_url: #{api_url}")
901
- @log.error("-> is_already_hashed: #{is_already_hashed}")
902
- @log.error("-> sent data:")
903
- @log.error(document)
904
- @log.error("--> verificator_id: "+ verification["verificator_id"])
905
- end
695
+ }
906
696
 
907
- next
697
+ lookup_set_match_found = true
908
698
  end
909
699
 
910
- rescue => e
911
- if @log.error?
912
- @log.error("[check] Blockstack.checkVerificator raised exception:")
913
- @log.error("#{e.class}, #{e.message}")
914
- @log.error("-> client_id: #{client_id}")
915
- @log.error("-> api_url: #{api_url}")
916
- @log.error("-> is_already_hashed: #{is_already_hashed}")
917
- @log.error("-> sent data:")
918
- @log.error(document)
919
- @log.error("--> verificator_id: "+ verification["verificator_id"])
700
+ if is_matching
701
+ break
920
702
  end
703
+ }
921
704
 
922
- raise e
705
+ if lookup_set_match_found
706
+ break
923
707
  end
924
708
 
925
- # b) check validator record in Blockstack (recursive)
926
- begin
927
-
928
- if !blockstackClient.checkValidator(verification["validator_id"])
929
- if @log.error?
930
- @log.error("[check] not a valid verification - failed to check validator record")
931
- @log.error("-> client_id: #{client_id}")
932
- @log.error("-> api_url: #{api_url}")
933
- @log.error("-> is_already_hashed: #{is_already_hashed}")
934
- @log.error("-> sent data:")
935
- @log.error(document)
936
- @log.error("--> validator_id: "+ verification["validator_id"])
937
- end
709
+ }
938
710
 
939
- next
940
- end
711
+ other_fields_index.each { |field, values|
941
712
 
942
- rescue => e
943
- if @log.error?
944
- @log.error("[check] Blockstack.checkValidator raised exception:")
945
- @log.error("#{e.class}, #{e.message}")
946
- @log.error("-> client_id: #{client_id}")
947
- @log.error("-> api_url: #{api_url}")
948
- @log.error("-> is_already_hashed: #{is_already_hashed}")
949
- @log.error("-> sent data:")
950
- @log.error(document)
951
- @log.error("--> validator_id: "+ verification["validator_id"])
952
- end
713
+ if values.length == 1
953
714
 
954
- raise e
715
+ values.take(1).each { |value, validated_count|
716
+ if value == sent_document[field]
717
+ result[field] = validated_count
718
+ else
719
+ possible_mistakes.push(field)
720
+ end
721
+ }
722
+
723
+ else
724
+ possible_mistakes.push(field)
955
725
  end
956
726
 
957
- # c) check verificator's signature
958
- verificator_pubkey = nil
727
+ }
959
728
 
960
- begin
729
+ return {
730
+ "status" => "success",
731
+ "possible_mistakes" => possible_mistakes,
732
+ "validated" => result
733
+ }
961
734
 
962
- verificator_pubkey = blockstackClient.getPublicKey(verification["verificator_id"])
735
+ end
963
736
 
964
- rescue => e
965
- if @log.error?
966
- @log.error("[check] Blockstack.getPublicKey raised exception:")
967
- @log.error("#{e.class}, #{e.message}")
968
- @log.error("-> client_id: #{client_id}")
969
- @log.error("-> api_url: #{api_url}")
970
- @log.error("-> is_already_hashed: #{is_already_hashed}")
971
- @log.error("-> sent data:")
972
- @log.error(document)
973
- @log.error("--> verificator_id: "+ verification["verificator_id"])
974
- end
737
+ end
975
738
 
976
- raise e
977
- end
739
+ end
740
+ end
978
741
 
979
- if verificator_pubkey == nil
980
- if @log.error?
981
- @log.error("[check] failed to retrieve public key for verificator")
982
- @log.error("-> client_id: #{client_id}")
983
- @log.error("-> api_url: #{api_url}")
984
- @log.error("-> is_already_hashed: #{is_already_hashed}")
985
- @log.error("-> sent data:")
986
- @log.error(document)
987
- @log.error("--> verificator_id: "+ verification["verificator_id"])
988
- end
742
+ def validate_data_points(data_points, documents)
989
743
 
990
- next
991
- end
744
+ output = {}
992
745
 
993
- if @log.debug?
994
- @log.debug("verificator pubkey:")
995
- @log.debug(verificator_pubkey)
996
- end
746
+ blockchainConnection = VChainClient::BlockchainConnection.new(@config)
997
747
 
998
- begin
999
-
1000
- if !signaturesHelper.checkVerificationSignature(field_hash, data_hash, verification["type"], verification["timestamp"], verification["verificator_id"], verificator_pubkey, Base64.decode64(verification["verificator_sig"]))
1001
- if @log.error?
1002
- @log.error("[check] not a valid verification - failed to check verificator signature")
1003
- @log.error("-> client_id: #{client_id}")
1004
- @log.error("-> api_url: #{api_url}")
1005
- @log.error("-> is_already_hashed: #{is_already_hashed}")
1006
- @log.error("-> sent data:")
1007
- @log.error(document)
1008
- @log.error("--> field_hash: #{field_hash}")
1009
- @log.error("--> data_hash")
1010
- @log.error("--> verification_type: "+ verification["type"])
1011
- @log.error("--> verification_timestamp: "+ verification["timestamp"].to_s)
1012
- @log.error("--> verificator_id: "+ verification["verificator_id"])
1013
- @log.error("--> verificator_pubkey: "+ verificator_pubkey)
1014
- @log.error("--> verificator_sig: "+ Base64.decode64(verification["verificator_sig"]))
1015
- end
748
+ blockstackClient = VChainClient::BlockstackClient.new(@config)
1016
749
 
1017
- next
1018
- end
750
+ signaturesHelper = VChainClient::Signatures.new(@config)
1019
751
 
1020
- rescue => e
1021
- if @log.error?
1022
- @log.error("[check] Signatures.checkVerificationSignature raised exception:")
1023
- @log.error("#{e.class}, #{e.message}")
1024
- @log.error("-> client_id: #{client_id}")
1025
- @log.error("-> api_url: #{api_url}")
1026
- @log.error("-> is_already_hashed: #{is_already_hashed}")
1027
- @log.error("-> sent data:")
1028
- @log.error(document)
1029
- @log.error("--> field_hash: #{field_hash}")
1030
- @log.error("--> data_hash")
1031
- @log.error("--> verification_type: "+ verification["type"])
1032
- @log.error("--> verification_timestamp: "+ verification["timestamp"].to_s)
1033
- @log.error("--> verificator_id: "+ verification["verificator_id"])
1034
- @log.error("--> verificator_pubkey: "+ verificator_pubkey)
1035
- @log.error("--> verificator_sig: "+ Base64.decode64(verification["verificator_sig"]))
1036
- end
752
+ documents_index = {}
1037
753
 
1038
- raise e
1039
- end
754
+ documents.each { |document|
755
+ hashed_doc = self.full_hash(document)
756
+ hashed_doc["original_doc_hash"] = self.get_doc_hash(document)
757
+ documents_index[hashed_doc["doc_hash"]] = hashed_doc
758
+ }
1040
759
 
1041
- # d) check validator's signature
1042
- validator_pubkey = nil
760
+ data_points.each { |data_point|
1043
761
 
1044
- begin
762
+ if !data_point.key?("blockchain_reciepts")
763
+ if @log.error?
764
+ @log.error("[check] not a valid data point - no blockchain_reciepts key")
765
+ @log.error(data_point)
766
+ end
1045
767
 
1046
- validator_pubkey = blockstackClient.getPublicKey(verification["validator_id"])
768
+ next
769
+ end
1047
770
 
1048
- rescue => e
1049
- if @log.error?
1050
- @log.error("[check] Blockstack.getPublicKey raised exception:")
1051
- @log.error("#{e.class}, #{e.message}")
1052
- @log.error("-> client_id: #{client_id}")
1053
- @log.error("-> api_url: #{api_url}")
1054
- @log.error("-> is_already_hashed: #{is_already_hashed}")
1055
- @log.error("-> sent data:")
1056
- @log.error(document)
1057
- @log.error("--> validator_id: "+ verification["validator_id"])
1058
- end
771
+ if data_point["blockchain_reciepts"].length <= 0
772
+ if @log.error?
773
+ @log.error("[check] not a valid data point - blockchain_reciepts is empty")
774
+ @log.error(data_point)
775
+ end
1059
776
 
1060
- raise e
1061
- end
777
+ next
778
+ end
1062
779
 
1063
- if validator_pubkey == nil
1064
- if @log.error?
1065
- @log.error("[check] failed to retrieve pubic key for validator")
1066
- @log.error("-> client_id: #{client_id}")
1067
- @log.error("-> api_url: #{api_url}")
1068
- @log.error("-> is_already_hashed: #{is_already_hashed}")
1069
- @log.error("-> sent data:")
1070
- @log.error(document)
1071
- @log.error("--> validator_id: "+ verification["validator_id"])
1072
- end
780
+ if !documents_index.key?(data_point["doc_hash"])
781
+ if @log.error?
782
+ @log.error("[check] not a valid data point - no such doc_hash in docs returned")
783
+ @log.error(data_point)
784
+ end
1073
785
 
1074
- next
1075
- end
786
+ next
787
+ end
1076
788
 
1077
- if @log.debug?
1078
- @log.debug("validator pubkey:")
1079
- @log.debug(validator_pubkey)
1080
- end
789
+ document = documents_index[data_point["doc_hash"]]
1081
790
 
1082
- begin
1083
-
1084
- if !signaturesHelper.checkVerificationSignature(field_hash, data_hash, verification["type"], verification["timestamp"], verification["validator_id"], validator_pubkey, Base64.decode64(verification["validator_sig"]))
1085
- if @log.error?
1086
- @log.error("[check] not a valid verification - failed to check verificator signature")
1087
- @log.error("-> client_id: #{client_id}")
1088
- @log.error("-> api_url: #{api_url}")
1089
- @log.error("-> is_already_hashed: #{is_already_hashed}")
1090
- @log.error("-> sent data:")
1091
- @log.error(document)
1092
- @log.error("--> field_hash: #{field_hash}")
1093
- @log.error("--> data_hash")
1094
- @log.error("--> verification_type: "+ verification["type"])
1095
- @log.error("--> verification_timestamp: "+ verification["timestamp"].to_s)
1096
- @log.error("--> validator_id: "+ verification["validator_id"])
1097
- @log.error("--> validator_pubkey: "+ validator_pubkey)
1098
- @log.error("--> validator_sig: "+ Base64.decode64(verification["validator_sig"]))
1099
- end
791
+ doc_hash = Digest::SHA512.hexdigest(document["original_doc_hash"])
1100
792
 
1101
- next
1102
- end
793
+ # 1a. check doc_hash
794
+ if doc_hash != data_point["doc_hash"]
795
+ if @log.error?
796
+ @log.error("[check] not a valid data point - doc_hash mismatch ("+ data_point["doc_hash"] +")")
797
+ end
1103
798
 
1104
- rescue => e
1105
- if @log.error?
1106
- @log.error("[check] Signatures.checkVerificationSignature raised exception:")
1107
- @log.error("#{e.class}, #{e.message}")
1108
- @log.error("-> client_id: #{client_id}")
1109
- @log.error("-> api_url: #{api_url}")
1110
- @log.error("-> is_already_hashed: #{is_already_hashed}")
1111
- @log.error("-> sent data:")
1112
- @log.error(document)
1113
- @log.error("--> field_hash: #{field_hash}")
1114
- @log.error("--> data_hash")
1115
- @log.error("--> verification_type: "+ verification["type"])
1116
- @log.error("--> verification_timestamp: "+ verification["timestamp"].to_s)
1117
- @log.error("--> validator_id: "+ verification["validator_id"])
1118
- @log.error("--> validator_pubkey: "+ validator_pubkey)
1119
- @log.error("--> validator_sig: "+ Base64.decode64(verification["validator_sig"]))
1120
- end
799
+ next
800
+ end
1121
801
 
1122
- raise e
1123
- end
802
+ # 1b. check field_hash
803
+ if !document.key?(data_point["field_hash"])
804
+ if @log.error?
805
+ @log.error("[check] not a valid data point - field_hash mismatch ("+ data_point["field_hash"] +")")
806
+ end
807
+
808
+ next
809
+ end
810
+
811
+ # 1c. check data_hash
812
+ data_hash = document[data_point["field_hash"]]
813
+ if data_hash != data_point["data_hash"]
814
+ if @log.error?
815
+ @log.error("[check] not a valid data point - data_hash mismatch ("+ data_hash +")")
816
+ end
817
+
818
+ next
819
+ end
820
+
821
+ # 1d. check data_point_hash
822
+ checksum_to_hash = data_point["field_hash"] + data_point["data_hash"] + data_point["doc_hash"] + data_point["type"] + data_point["issuer_sig"] + data_point["issuer_id"] + data_point["validator_sig"] + data_point["validator_id"] + data_point["weight"] + data_point["timestamp"]
823
+ checksum = Digest::SHA512.hexdigest(checksum_to_hash)
824
+ if checksum != data_point["data_point_hash"]
825
+ if @log.error?
826
+ @log.error("[check] not a valid data point - checksum mismatch ("+ checksum +")")
827
+ end
828
+
829
+ next
830
+ end
831
+
832
+ # 2. check verification_hash to be in target_proof's
833
+ # first element
834
+
835
+ reciepts_validated = 0
836
+
837
+ data_point["blockchain_reciepts"].each { |reciept|
838
+
839
+ if !reciept.key?("target_proof")
840
+ if @log.error?
841
+ @log.error("[check] not a valid blockchain reciept - no target_proof")
842
+ @log.error(reciept)
843
+ end
844
+
845
+ break
846
+ end
847
+
848
+ if reciept["target_proof"].length <= 0
849
+ if @log.error?
850
+ @log.error("[check] not a valid blockchain reciept - target_proof length is <= 0")
851
+ @log.error(reciept)
852
+ end
853
+
854
+ break
855
+ end
856
+
857
+ if reciept["target_proof"][0]["left"] != data_point["data_point_hash"] && reciept["target_proof"][0]["right"] != data_point["data_point_hash"]
858
+ if @log.error?
859
+ @log.error("[check] not a valid blockchain reciept - no target element in target_proof.0")
860
+ @log.error(reciept)
861
+ end
862
+
863
+ break
864
+ end
865
+
866
+ # verification_hash is in tree
867
+ # and in right position
868
+ # now,
869
+
870
+ # 3. check tree convergence to root hash
871
+ # and compare this computed root hash
872
+ # with merkle_tree_root_hash from response
873
+
874
+ computed_tree_root_hash = self.build_merkle_tree(reciept["target_proof"], reciept["timestamp"])
875
+
876
+ if computed_tree_root_hash == nil
877
+ if @log.error?
878
+ @log.error("[check] not a valid blockchain reciept - failed to compute tree root hash")
879
+ @log.error(reciept)
880
+ end
881
+
882
+ break
883
+ end
884
+ if computed_tree_root_hash != reciept["merkle_tree_root_hash"]
885
+ if @log.error?
886
+ @log.error("[check] not a valid blockchain reciept - merkle tree root hash mismatch ("+ computed_tree_root_hash +", "+ reciept["merkle_tree_root_hash"] +")")
887
+ @log.error(reciept)
888
+ end
889
+
890
+ break
891
+ end
892
+
893
+ last_proof_index = reciept["target_proof"].length - 1
894
+ reciept_stored_last_parent = reciept["target_proof"][last_proof_index]["parent"]
895
+ if reciept_stored_last_parent != computed_tree_root_hash
896
+ if @log.error?
897
+ @log.error("[check] not a valid blockchain reciept - last stored parent != computed_tree_root_hash ("+ reciept_stored_last_parent +", "+ computed_tree_root_hash +")")
898
+ @log.error(reciept)
899
+ end
900
+
901
+ break
902
+ end
903
+
904
+ # 4. check OP_RETURN in Bitcoin's tx,
905
+ # compare it to computed root hash of a tree
906
+ # retrieve some info from tx to verify signature
907
+ tx = nil
908
+
909
+ begin
910
+
911
+ tx = blockchainConnection.getTx(reciept["blockchain_txid"])
912
+
913
+ rescue => e
914
+ if @log.error?
915
+ @log.error("[check] BlockchainConnection.getTx raised exception:")
916
+ @log.error("#{e.class}, #{e.message}")
917
+ end
918
+
919
+ raise e
920
+ end
921
+
922
+ if tx == nil
923
+ if @log.error?
924
+ @log.error("[check] not a valid blockchain reciept - failed to retrieve TX from Blockchain")
925
+ @log.error(reciept)
926
+ end
927
+
928
+ break
929
+ end
930
+
931
+ if tx["block_hash"] != reciept["blockchain_block_hash"]
932
+ if @log.error?
933
+ @log.error("[check] not a valid blockchain reciept - block_hash mismatch")
934
+ @log.error(tx)
935
+ @log.error(reciept)
936
+ end
937
+
938
+ break
939
+ end
940
+
941
+ if tx["block_timestamp"] != reciept["blockchain_timestamp"]
942
+ if @log.error?
943
+ @log.error("[check] not a valid blockchain reciept - timestamp mismatch")
944
+ @log.error(tx)
945
+ @log.error(reciept)
946
+ end
947
+
948
+ break
949
+ end
1124
950
 
1125
- # 7. timestamps checking
1126
- # TODO
951
+ if tx["op_return"] != computed_tree_root_hash
952
+ if @log.error?
953
+ @log.error("[check] not a valid blockchain reciept - op_return mismatch")
954
+ @log.error(computed_tree_root_hash)
955
+ @log.error(tx)
956
+ @log.error(reciept)
957
+ end
958
+
959
+ break
960
+ end
1127
961
 
962
+ blockchain_txid = reciept["blockchain_txid"];
963
+ blockchain_block_hash = tx["block_hash"];
964
+ blockchain_timestamp = tx["block_timestamp"];
965
+
966
+ # 5. check tree signature:
967
+ # a) federative server record in Blockstack (recursive)
968
+ # b) tree_signature
969
+
970
+ # a) federative server record in Blockstack (recursive)
971
+ begin
1128
972
 
1129
- if !validated_verifications.key?(field)
1130
- validated_verifications[field] = 0
973
+ if !blockstackClient.checkFederativeServer(reciept["federative_server_id"])
974
+ if @log.error?
975
+ @log.error("[check] not a valid blockchain reciept - failed to check federative server")
976
+ @log.error(reciept)
1131
977
  end
1132
- validated_verifications[field] = validated_verifications[field] + 1
1133
- }
1134
978
 
1135
- else
1136
- if @log.debug?
1137
- vers_count = 0
1138
- if v.key?("verifications") && v["verifications"].length > 0
1139
- vers_count = v["verifications"].length.to_s
979
+ break
980
+ end
981
+
982
+ rescue => e
983
+ if @log.error?
984
+ @log.error("[check] Blockstack.checkFederativeServer raised exception:")
985
+ @log.error("#{e.class}, #{e.message}")
986
+ @log.error(reciept)
987
+ end
988
+
989
+ raise e
990
+ end
991
+
992
+ # b) check tree signature
993
+ federative_server_pubkey = nil
994
+
995
+ begin
996
+
997
+ federative_server_pubkey = blockstackClient.getPublicKey(reciept["federative_server_id"])
998
+
999
+ rescue => e
1000
+ if @log.error?
1001
+ @log.error("[check] Blockstack.getPublicKey raised exception:")
1002
+ @log.error("#{e.class}, #{e.message}")
1003
+ @log.error(reciept)
1004
+ end
1005
+
1006
+ raise e
1007
+ end
1008
+
1009
+ if federative_server_pubkey == nil
1010
+ if @log.error?
1011
+ @log.error("[check] not a valid blockchain reciept - failed to retrieve public key for federative server '"+ reciept["federative_server_id"] +"'")
1012
+ @log.error(reciept)
1013
+ end
1014
+
1015
+ break
1016
+ end
1017
+
1018
+ begin
1019
+
1020
+ if !signaturesHelper.checkTreeSignature(computed_tree_root_hash, blockchain_txid, blockchain_block_hash, blockchain_timestamp, reciept["federative_server_id"], reciept["federative_server_version"], Base64.decode64(reciept["tree_signature"]), federative_server_pubkey)
1021
+ if @log.error?
1022
+ @log.error("[check] not a valid blockchain reciept - failed to verify tree signature")
1023
+ @log.error(reciept)
1024
+ @log.error("--> computed_tree_root_hash: #{computed_tree_root_hash}")
1025
+ @log.error("--> blockchain_txid: #{blockchain_txid}")
1026
+ @log.error("--> blockchain_block_hash: #{blockchain_block_hash}")
1027
+ @log.error("--> blockchain_timestamp: #{blockchain_timestamp}")
1028
+ @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
1029
+ @log.error("--> federative_server_version: "+ reciept["federative_server_version"])
1030
+ @log.error("--> tree_signature: "+ Base64.decode64(reciept["tree_signature"]))
1031
+ @log.error("--> federative_server_pubkey: #{federative_server_pubkey}")
1140
1032
  end
1141
1033
 
1142
- @log.debug("[check] skip '"+ field +"', number of recieved verifications: "+ vers_count.to_s)
1034
+ break
1035
+ end
1036
+
1037
+ rescue => e
1038
+ if @log.error?
1039
+ @log.error("[check] Blockstack.checkTreeSignature raised exception:")
1040
+ @log.error("#{e.class}, #{e.message}")
1041
+ @log.error(reciept)
1042
+ @log.error("--> computed_tree_root_hash: #{computed_tree_root_hash}")
1043
+ @log.error("--> blockchain_txid: #{blockchain_txid}")
1044
+ @log.error("--> blockchain_block_hash: #{blockchain_block_hash}")
1045
+ @log.error("--> blockchain_timestamp: #{blockchain_timestamp}")
1046
+ @log.error("--> federative_server_id: "+ reciept["federative_server_id"])
1047
+ @log.error("--> federative_server_version: "+ reciept["federative_server_version"])
1048
+ @log.error("--> tree_signature: "+ Base64.decode64(reciept["tree_signature"]))
1049
+ @log.error("--> federative_server_pubkey: #{federative_server_pubkey}")
1143
1050
  end
1144
- end
1051
+
1052
+ raise e
1053
+ end
1054
+
1055
+ reciepts_validated += 1
1145
1056
  }
1146
1057
 
1147
- if @log.debug?
1148
- @log.debug("[check] temp validated verifications:")
1149
- @log.debug(validated_verifications)
1058
+ if reciepts_validated != data_point["blockchain_reciepts"].length
1059
+ if @log.error?
1060
+ @log.error("[check] not a valid verification - not every reciept were validated")
1061
+ end
1062
+
1063
+ next
1150
1064
  end
1151
1065
 
1152
- # check input fields
1153
- input.each_with_index { |field,index|
1154
- if field[0] != 'type' && field[0] != 'client_id'
1155
- if !validated_verifications.key?(field[0])
1156
- validated_verifications[field[0]] = 0
1066
+ # 6. check verification signatures:
1067
+ # a) check verificator record in Blockstack (recursive)
1068
+ # b) check validator record in Blockstack (recursive)
1069
+ # c) verificator_sig
1070
+ # d) validtor_sig
1071
+
1072
+ # a) check verificator record in Blockstack (recursive)
1073
+ begin
1074
+
1075
+ if !blockstackClient.checkVerificator(data_point["issuer_id"])
1076
+ if @log.error?
1077
+ @log.error("[check] not a valid verification - failed to check verificator record")
1078
+ @log.error("--> verificator_id: "+ data_point["issuer_id"])
1157
1079
  end
1080
+
1081
+ next
1158
1082
  end
1159
- }
1083
+
1084
+ rescue => e
1085
+ if @log.error?
1086
+ @log.error("[check] Blockstack.checkVerificator raised exception:")
1087
+ @log.error("#{e.class}, #{e.message}")
1088
+ @log.error("--> verificator_id: "+ data_point["issuer_id"])
1089
+ end
1090
+
1091
+ raise e
1092
+ end
1093
+
1094
+ # b) check validator record in Blockstack (recursive)
1095
+ begin
1096
+
1097
+ if !blockstackClient.checkValidator(data_point["validator_id"])
1098
+ if @log.error?
1099
+ @log.error("[check] not a valid verification - failed to check validator record")
1100
+ @log.error("--> validator_id: "+ data_point["validator_id"])
1101
+ end
1102
+
1103
+ next
1104
+ end
1105
+
1106
+ rescue => e
1107
+ if @log.error?
1108
+ @log.error("[check] Blockstack.checkValidator raised exception:")
1109
+ @log.error("#{e.class}, #{e.message}")
1110
+ @log.error("--> validator_id: "+ data_point["validator_id"])
1111
+ end
1112
+
1113
+ raise e
1114
+ end
1115
+
1116
+ # c) check verificator's signature
1117
+ verificator_pubkey = nil
1118
+
1119
+ begin
1120
+
1121
+ verificator_pubkey = blockstackClient.getPublicKey(data_point["issuer_id"])
1122
+
1123
+ rescue => e
1124
+ if @log.error?
1125
+ @log.error("[check] Blockstack.getPublicKey raised exception:")
1126
+ @log.error("#{e.class}, #{e.message}")
1127
+ @log.error("--> verificator_id: "+ data_point["issuer_id"])
1128
+ end
1129
+
1130
+ raise e
1131
+ end
1132
+
1133
+ if verificator_pubkey == nil
1134
+ if @log.error?
1135
+ @log.error("[check] failed to retrieve public key for verificator")
1136
+ @log.error(document)
1137
+ @log.error("--> verificator_id: "+ data_point["issuer_id"])
1138
+ end
1139
+
1140
+ next
1141
+ end
1160
1142
 
1161
1143
  if @log.debug?
1162
- @log.debug("[check] resulted validated verifications:")
1163
- @log.debug(validated_verifications)
1144
+ @log.debug("verificator pubkey:")
1145
+ @log.debug(verificator_pubkey)
1164
1146
  end
1165
- end
1166
1147
 
1167
- if res["status"] == "ERROR" || res["status"] == "error"
1148
+ begin
1168
1149
 
1169
- if res["error_reason_code"] == "DOCUMENT_POSSIBLE_MISTAKES"
1150
+ if !signaturesHelper.checkVerificationSignature(data_point["field_hash"], data_point["data_hash"], data_point["doc_hash"], data_point["type"], data_point["weight"], data_point["timestamp"], data_point["issuer_id"], verificator_pubkey, Base64.decode64(data_point["issuer_sig"]))
1151
+ if @log.error?
1152
+ @log.error("[check] not a valid verification - failed to check verificator signature")
1153
+ @log.error("--> field_hash: "+ data_point["field_hash"])
1154
+ @log.error("--> data_hash: "+ data_point["data_hash"])
1155
+ @log.error("--> doc_hash: "+ data_point["doc_hash"])
1156
+ @log.error("--> type: "+ data_point["type"])
1157
+ @log.error("--> weight: "+ data_point["weight"].to_s)
1158
+ @log.error("--> timestamp: "+ data_point["timestamp"].to_s)
1159
+ @log.error("--> verificator_id: "+ data_point["issuer_id"])
1160
+ @log.error("--> verificator_pubkey: "+ verificator_pubkey)
1161
+ @log.error("--> verificator_sig: "+ data_point["issuer_sig"])
1162
+ end
1170
1163
 
1171
- possible_mistakes_output = {}
1164
+ next
1165
+ end
1172
1166
 
1173
- if res.key?("possible_mistakes")
1174
- res["possible_mistakes"].each_with_index { |field,index|
1167
+ rescue => e
1168
+ if @log.error?
1169
+ @log.error("[check] Signatures.checkVerificationSignature raised exception:")
1170
+ @log.error("#{e.class}, #{e.message}")
1171
+ @log.error("--> field_hash: "+ data_point["field_hash"])
1172
+ @log.error("--> data_hash: "+ data_point["data_hash"])
1173
+ @log.error("--> doc_hash: "+ data_point["doc_hash"])
1174
+ @log.error("--> type: "+ data_point["type"])
1175
+ @log.error("--> weight: "+ data_point["weight"].to_s)
1176
+ @log.error("--> timestamp: "+ data_point["timestamp"].to_s)
1177
+ @log.error("--> verificator_id: "+ data_point["issuer_id"])
1178
+ @log.error("--> verificator_pubkey: "+ verificator_pubkey)
1179
+ @log.error("--> verificator_sig: "+ data_point["issuer_sig"])
1180
+ end
1175
1181
 
1176
- possible_mistakes_output[field[0]] = validated_verifications[field[0]]
1182
+ raise e
1183
+ end
1177
1184
 
1178
- validated_verifications.delete(field[0])
1179
- }
1185
+ # d) check validator's signature
1186
+ validator_pubkey = nil
1187
+
1188
+ begin
1189
+
1190
+ validator_pubkey = blockstackClient.getPublicKey(data_point["validator_id"])
1191
+
1192
+ rescue => e
1193
+ if @log.error?
1194
+ @log.error("[check] Blockstack.getPublicKey raised exception:")
1195
+ @log.error("#{e.class}, #{e.message}")
1196
+ @log.error("--> validator_id: "+ data_point["validator_id"])
1180
1197
  end
1181
1198
 
1182
- return {
1183
- "status" => "error",
1184
- "possible_mistakes" => possible_mistakes_output,
1185
- "validated" => validated_verifications,
1186
- "reason" => res["error_reason_code"]
1187
- }
1199
+ raise e
1188
1200
  end
1189
1201
 
1190
- return {
1191
- "status" => "error",
1192
- "reason" => res["error_reason_code"]
1193
- }
1202
+ if validator_pubkey == nil
1203
+ if @log.error?
1204
+ @log.error("[check] failed to retrieve pubic key for validator")
1205
+ @log.error("--> validator_id: "+ data_point["validator_id"])
1206
+ end
1194
1207
 
1195
- else
1196
- # success result
1197
- return validated_verifications
1208
+ next
1209
+ end
1198
1210
 
1199
- end
1211
+ if @log.debug?
1212
+ @log.debug("validator pubkey:")
1213
+ @log.debug(validator_pubkey)
1214
+ end
1215
+
1216
+ begin
1217
+
1218
+ if !signaturesHelper.checkVerificationSignature(data_point["field_hash"], data_point["data_hash"], data_point["doc_hash"], data_point["type"], data_point["weight"], data_point["timestamp"], data_point["validator_id"], validator_pubkey, Base64.decode64(data_point["validator_sig"]))
1219
+ if @log.error?
1220
+ @log.error("[check] not a valid verification - failed to check validator signature")
1221
+ @log.error("--> field_hash: "+ data_point["field_hash"])
1222
+ @log.error("--> data_hash: "+ data_point["data_hash"])
1223
+ @log.error("--> doc_hash: "+ data_point["doc_hash"])
1224
+ @log.error("--> type: "+ data_point["type"])
1225
+ @log.error("--> weight: "+ data_point["weight"].to_s)
1226
+ @log.error("--> timestamp: "+ data_point["timestamp"].to_s)
1227
+ @log.error("--> validator_id: "+ data_point["validator_id"])
1228
+ @log.error("--> validator_pubkey: "+ validator_pubkey)
1229
+ @log.error("--> validator_sig: "+ Base64.encode64(data_point["validator_sig"]))
1230
+ end
1231
+
1232
+ next
1233
+ end
1234
+
1235
+ rescue => e
1236
+ if @log.error?
1237
+ @log.error("[check] Signatures.checkVerificationSignature raised exception:")
1238
+ @log.error("#{e.class}, #{e.message}")
1239
+ @log.error("--> field_hash: "+ data_point["field_hash"])
1240
+ @log.error("--> data_hash: "+ data_point["data_hash"])
1241
+ @log.error("--> doc_hash: "+ data_point["doc_hash"])
1242
+ @log.error("--> type: "+ data_point["type"])
1243
+ @log.error("--> weight: "+ data_point["weight"].to_s)
1244
+ @log.error("--> timestamp: "+ data_point["timestamp"].to_s)
1245
+ @log.error("--> validator_id: "+ data_point["validator_id"])
1246
+ @log.error("--> validator_pubkey: "+ validator_pubkey)
1247
+ @log.error("--> validator_sig: "+ Base64.encode64(data_point["validator_sig"]))
1248
+ end
1249
+
1250
+ raise e
1251
+ end
1252
+
1253
+ # 7. timestamps checking
1254
+ # TODO
1255
+
1256
+ if !output.key?(data_point["doc_hash"])
1257
+ output[data_point["doc_hash"]] = {}
1258
+ end
1259
+ if !output[data_point["doc_hash"]].key?(data_point["field_hash"])
1260
+ output[data_point["doc_hash"]][data_point["field_hash"]] = 0
1261
+ end
1262
+
1263
+ output[data_point["doc_hash"]][data_point["field_hash"]] += 1
1264
+ }
1265
+
1266
+ return output
1200
1267
  end
1201
1268
 
1202
1269
  def self.generateBlockstackCommand(config)