vchain_client 1.0.15 → 1.0.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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)