vchain_client 1.0.1 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa130280366a0e4e56548c9a15435e04db999452
4
- data.tar.gz: 4d18e892a688984d0687191cf2ea6420214613a8
3
+ metadata.gz: 22d66dc123ee989151f30fd3788b468c62026c78
4
+ data.tar.gz: 685b5f411fb7c965f493facc83d72ab886f9045d
5
5
  SHA512:
6
- metadata.gz: ed11a5f60b243789441434726c5724e24964cefaf5c4b0d36059723170396cbdc94bbf6f315a4d18016cb0a317ad52c4c631af382a8a213248aa97e2b350f269
7
- data.tar.gz: 414e34150172826ceab35559cb32d7fad5c1fe99256a526aa4e7613a6490caeb98c0e84475c3681cc685a2805898ce3c4711bf4711e3f53bae44efd9574aeb82
6
+ metadata.gz: 82145e5468d9b71fe0b9c95cc1b836ae06a9b53caecb5ed1e18a64e0be4562fd55a2246b22dc49a8485add020d45f763141e6c14dedf64e8301a1457d86b5fc8
7
+ data.tar.gz: d2ae23783d5ed7ae0b6519edffca250e63663c8d8b4cbde5b246f4d062eb31601ed0f34ef29616755e644a43769b4afb31babe90adb2cf2eaa79d5dffdb85215
@@ -2,6 +2,8 @@ module VChainClient
2
2
 
3
3
  class BitcoindBlockchainAdapter < VChainClient::BlockchainAdapter
4
4
 
5
+ @log = nil
6
+
5
7
  @server = nil
6
8
  @port = nil
7
9
  @rpc_username = nil
@@ -12,22 +14,76 @@ module VChainClient
12
14
  @port = port
13
15
  @rpc_username = rpc_username
14
16
  @rpc_password = rpc_password
17
+
18
+ @log = Log4r::Logger["vchain_client"]
15
19
  end
16
20
 
21
+ def getName()
22
+ return "BitcoindBlockchainAdapter"
23
+ end
24
+
17
25
  def getTx(txid)
18
- raw_tx = self.getRawTx(txid)
26
+
27
+ if @log.debug?
28
+ @log.debug("[Bitcoind.getTx] input:")
29
+ @log.debug("-> txid: #{txid}")
30
+ @log.debug("-> server: #{@server}")
31
+ @log.debug("-> port: #{@port}")
32
+ end
33
+
34
+ raw_tx = nil
35
+
36
+ begin
37
+
38
+ raw_tx = self.getRawTx(txid)
39
+
40
+ rescue => e
41
+ if @log.error?
42
+ @log.error("[Bitcoind.getTx] getRawTx raised exception:")
43
+ @log.error("#{e.class}, #{e.message}")
44
+ @log.error("-> txid: #{txid}")
45
+ @log.error("-> server: #{@server}")
46
+ @log.error("-> port: #{@port}")
47
+ @log.error("--> txid: #{txid}")
48
+ end
49
+
50
+ raise e
51
+ end
19
52
 
20
53
  if raw_tx != nil
54
+
21
55
  if raw_tx.key?("confirmations")
56
+
22
57
  if raw_tx["confirmations"] > 5
58
+
23
59
  if raw_tx.key?("blockhash")
60
+
24
61
  if raw_tx.key?("blocktime")
25
62
 
26
- op_return = self.getOpReturn(raw_tx)
63
+ op_return = nil
64
+
65
+ begin
66
+
67
+ op_return = self.getOpReturn(raw_tx)
68
+
69
+ rescue => e
70
+ if @log.error?
71
+ @log.error("[Bitcoind.getTx] getOpReturn raised exception:")
72
+ @log.error("#{e.class}, #{e.message}")
73
+ @log.error("-> txid: #{txid}")
74
+ @log.error("--> raw_tx:")
75
+ @log.error(raw_tx)
76
+ end
77
+
78
+ raise e
79
+ end
27
80
 
28
81
  if op_return != nil
82
+
29
83
  prefix = op_return[0..2]
84
+
30
85
  if prefix == "VCH"
86
+
31
87
  op_return = op_return[3..op_return.length]
32
88
 
33
89
  return {
@@ -36,19 +92,95 @@ module VChainClient
36
92
  "block_timestamp" => raw_tx["blocktime"],
37
93
  "op_return" => op_return
38
94
  }
95
+
96
+ else
97
+ if @log.error?
98
+ @log.error("[Bitcoind.getTx] wrong prefix '#{prefix}'")
99
+ @log.error("-> txid: #{txid}")
100
+ @log.error("-> server: #{@server}")
101
+ @log.error("-> port: #{@port}")
102
+ @log.error("-> raw_tx:")
103
+ @log.error(raw_tx)
104
+ end
105
+ end
106
+
107
+ else
108
+ if @log.error?
109
+ @log.error("[Bitcoind.getTx] failed to get OP_RETURN")
110
+ @log.error("-> txid: #{txid}")
111
+ @log.error("-> server: #{@server}")
112
+ @log.error("-> port: #{@port}")
113
+ @log.error("-> raw_tx:")
114
+ @log.error(raw_tx)
39
115
  end
40
116
  end
41
117
 
118
+ else
119
+ if @log.error?
120
+ @log.error("[Bitcoind.getTx] no 'block_hash' field in response")
121
+ @log.error("-> txid: #{txid}")
122
+ @log.error("-> server: #{@server}")
123
+ @log.error("-> port: #{@port}")
124
+ @log.error("-> raw_tx:")
125
+ @log.error(raw_tx)
126
+ end
127
+ end
128
+
129
+ else
130
+ if @log.error?
131
+ @log.error("[Bitcoind.getTx] no 'block_hash' field in response")
132
+ @log.error("-> txid: #{txid}")
133
+ @log.error("-> server: #{@server}")
134
+ @log.error("-> port: #{@port}")
135
+ @log.error("-> raw_tx:")
136
+ @log.error(raw_tx)
42
137
  end
43
138
  end
139
+
140
+ else
141
+ if @log.error?
142
+ @log.error("[Bitcoind.getTx] less than 6 confirmations")
143
+ @log.error("-> txid: #{txid}")
144
+ @log.error("-> server: #{@server}")
145
+ @log.error("-> port: #{@port}")
146
+ @log.error("-> raw_tx:")
147
+ @log.error(raw_tx)
148
+ end
149
+ end
150
+
151
+ else
152
+ if @log.error?
153
+ @log.error("[Bitcoind.getTx] no 'confirmations' field")
154
+ @log.error("-> txid: #{txid}")
155
+ @log.error("-> server: #{@server}")
156
+ @log.error("-> port: #{@port}")
157
+ @log.error("-> raw_tx:")
158
+ @log.error(raw_tx)
44
159
  end
45
160
  end
161
+
162
+ else
163
+ if @log.error?
164
+ @log.error("[Bitcoind.getTx] empty raw_tx")
165
+ @log.error("-> txid: #{txid}")
166
+ @log.error("-> server: #{@server}")
167
+ @log.error("-> port: #{@port}")
168
+ @log.error("--> txid: #{txid}")
169
+ end
46
170
  end
47
171
 
48
172
  return nil
49
173
  end
50
174
 
51
175
  def getRawTx(txid)
176
+
177
+ if @log.debug?
178
+ @log.debug("[Bitcoind.getRawTx] input:")
179
+ @log.debug("-> txid: #{txid}")
180
+ @log.debug("-> server: #{@server}")
181
+ @log.debug("-> port: #{@port}")
182
+ end
183
+
52
184
  request = {
53
185
  "id" => Random.rand(0...999999),
54
186
  "method" => "getrawtransaction",
@@ -62,14 +194,38 @@ module VChainClient
62
194
  req = RestClient.post(url, request.to_json)
63
195
 
64
196
  if req.code != 200
197
+ if @log.error?
198
+ @log.error("[Bitcoind.getRawTx] RestClient.post return code "+ req.code)
199
+ @log.error("-> txid: #{txid}")
200
+ @log.error("-> server: #{@server}")
201
+ @log.error("-> port: #{@port}")
202
+ @log.error("-> request:")
203
+ @log.error(request)
204
+ end
205
+
65
206
  return nil
66
207
  end
67
208
 
209
+ if @log.debug?
210
+ @log.debug("[Bitcoind.getRawTx] response:")
211
+ @log.debug(req.body)
212
+ end
213
+
68
214
  raw_tx = JSON.parse req.body
69
215
 
70
216
  return raw_tx["result"]
71
217
 
72
218
  rescue => e
219
+ if @log.error?
220
+ @log.error("[Bitcoind.getRawTx] RestClient.post raised exception:")
221
+ @log.error("#{e.class}, #{e.message}")
222
+ @log.error("-> txid: #{txid}")
223
+ @log.error("-> server: #{@server}")
224
+ @log.error("-> port: #{@port}")
225
+ @log.error("-> request:")
226
+ @log.error(request)
227
+ end
228
+
73
229
  raise e
74
230
  end
75
231
 
@@ -77,12 +233,22 @@ module VChainClient
77
233
  end
78
234
 
79
235
  def getOpReturn(raw_tx)
236
+
237
+ if @log.debug?
238
+ @log.debug("[Bitcoind.getOpReturn] input:")
239
+ @log.debug("-> raw_tx:")
240
+ @log.debug(raw_tx)
241
+ end
242
+
80
243
  if raw_tx != nil
244
+
81
245
  tx_unpacked = {}
82
246
  tx_unpacked["vout"] = []
83
247
 
84
248
  if raw_tx.key?("vout")
249
+
85
250
  if raw_tx["vout"].length > 0
251
+
86
252
  raw_tx["vout"].each_with_index { |vout,index|
87
253
  vout_t = {}
88
254
 
@@ -120,11 +286,17 @@ module VChainClient
120
286
  return scriptPubKeyBinary[4..scriptPubKeyBinary[2].ord()+1+256*scriptPubKeyBinary[3].ord()+1]
121
287
  end
122
288
  end
123
-
124
289
  }
125
290
 
126
291
  end
127
292
  end
293
+
294
+ else
295
+ if @log.error?
296
+ @log.error("[Bitcoind.getOpReturn] raw_tx is nil")
297
+ @log.error("-> raw_tx:")
298
+ @log.error(raw_tx)
299
+ end
128
300
  end
129
301
 
130
302
  return nil
@@ -6,6 +6,10 @@ module VChainClient
6
6
  return nil
7
7
  end
8
8
 
9
+ def getName()
10
+ return "abstract"
11
+ end
12
+
9
13
  end
10
14
 
11
15
  end
@@ -10,7 +10,8 @@ module VChainClient
10
10
  return VChainClient::BlockcypherBlockchainAdapter.new(config["api_token"])
11
11
  end
12
12
 
13
- return nil
13
+ raise "No such adapter '#{type}'"
14
+
14
15
  end
15
16
 
16
17
  end
@@ -2,23 +2,62 @@ module VChainClient
2
2
 
3
3
  class BlockchainConnection
4
4
 
5
+ @log = nil
6
+
5
7
  @config = nil
6
8
 
7
9
  def initialize(config)
8
10
  @config = config
11
+
12
+ @log = Log4r::Logger["vchain_client"]
9
13
  end
10
14
 
11
15
  def getTx(txid)
12
16
 
17
+ if @log.debug?
18
+ @log.debug("[BlockchainConnection.getTx] input:")
19
+ @log.debug("-> txid: #{txid}")
20
+ end
21
+
13
22
  adapters = []
14
23
 
24
+ if !@config.key?("blockchain_adapters")
25
+ raise "There are no blockchain_adapters in config"
26
+ end
27
+
15
28
  config_adapters = @config["blockchain_adapters"]
16
29
 
30
+ if config_adapters.length <= 0
31
+ raise "There are no blockchain_adapters in config"
32
+ end
33
+
17
34
  config_adapters.each { |adapter_config|
18
- adapter = VChainClient::BlockchainAdapterFactory.getAdapter(adapter_config["type"], adapter_config)
35
+
36
+ begin
37
+
38
+ adapter = VChainClient::BlockchainAdapterFactory.getAdapter(adapter_config["type"], adapter_config)
39
+
40
+ rescue => e
41
+ if @log.error?
42
+ @log.error("[BlockchainConnection.getTx] BlockchainAdapterFactory.getAdapter raised exception:")
43
+ @log.error("#{e.class}, #{e.message}")
44
+ @log.error("-> txid: #{txid}")
45
+ @log.error("--> type: "+ adapter_config["type"])
46
+ end
47
+
48
+ raise e
49
+ end
19
50
 
20
51
  if adapter != nil
21
- adapters.push(adapter)
52
+
53
+ adapters.push(adapter)
54
+
55
+ else
56
+ if @log.error?
57
+ @log.error("[BlockchainConnection.getTx] failed to init BlockchainAdapter")
58
+ @log.error("-> txid: #{txid}")
59
+ @log.error("--> type: "+ adapter_config["type"])
60
+ end
22
61
  end
23
62
  }
24
63
 
@@ -31,18 +70,65 @@ module VChainClient
31
70
 
32
71
  adapters.each { |adapter|
33
72
 
34
- tx = adapter.getTx(txid)
73
+ tx = nil
74
+
75
+ begin
76
+
77
+ tx = adapter.getTx(txid)
78
+
79
+ rescue => e
80
+ if @log.error?
81
+ @log.error("[BlockchainConnection.getTx] adapter.getTx raised exception:")
82
+ @log.error("#{e.class}, #{e.message}")
83
+ @log.error("-> txid: #{txid}")
84
+ @log.error("--> txid: #{txid}")
85
+ @log.error("--> adapter: "+ adapter.getName())
86
+ end
87
+
88
+ raise e
89
+ end
35
90
 
36
91
  if tx == nil
92
+ if @log.error?
93
+ @log.error("[BlockchainConnection.getTx] failed to get tx")
94
+ @log.error("-> txid: #{txid}")
95
+ @log.error("--> txid: #{txid}")
96
+ @log.error("--> adapter: "+ adapter.getName())
97
+ end
98
+
37
99
  return nil
38
100
  end
101
+
39
102
  if !tx.key?("block_hash")
103
+ if @log.error?
104
+ @log.error("[BlockchainConnection.getTx] no 'block_hash' field")
105
+ @log.error("-> txid: #{txid}")
106
+ @log.error("--> txid: #{txid}")
107
+ @log.error("--> adapter: "+ adapter.getName())
108
+ end
109
+
40
110
  return nil
41
111
  end
112
+
42
113
  if !tx.key?("block_timestamp")
114
+ if @log.error?
115
+ @log.error("[BlockchainConnection.getTx] no 'block_timestamp' field")
116
+ @log.error("-> txid: #{txid}")
117
+ @log.error("--> txid: #{txid}")
118
+ @log.error("--> adapter: "+ adapter.getName())
119
+ end
120
+
43
121
  return nil
44
122
  end
123
+
45
124
  if tx["block_hash"] == nil || tx["block_hash"] == ""
125
+ if @log.error?
126
+ @log.error("[BlockchainConnection.getTx] 'block_hash' field is empty")
127
+ @log.error("-> txid: #{txid}")
128
+ @log.error("--> txid: #{txid}")
129
+ @log.error("--> adapter: "+ adapter.getName())
130
+ end
131
+
46
132
  return nil
47
133
  end
48
134
 
@@ -52,15 +138,46 @@ module VChainClient
52
138
  op_return = tx["op_return"]
53
139
 
54
140
  if prev_size != nil && prev_size != size
141
+ if @log.error?
142
+ @log.error("[BlockchainConnection.getTx] size mismatch")
143
+ @log.error("-> txid: #{txid}")
144
+ @log.error("--> txid: #{txid}")
145
+ @log.error("--> adapter: "+ adapter.getName())
146
+ end
147
+
55
148
  return nil
56
149
  end
150
+
57
151
  if prev_block_hash != nil && prev_block_hash != block_hash
152
+ if @log.error?
153
+ @log.error("[BlockchainConnection.getTx] block_hash mismatch")
154
+ @log.error("-> txid: #{txid}")
155
+ @log.error("--> txid: #{txid}")
156
+ @log.error("--> adapter: "+ adapter.getName())
157
+ end
158
+
58
159
  return nil
59
160
  end
161
+
60
162
  if prev_block_timestamp != nil && prev_block_timestamp != block_timestamp
163
+ if @log.error?
164
+ @log.error("[BlockchainConnection.getTx] block_timestamp mismatch")
165
+ @log.error("-> txid: #{txid}")
166
+ @log.error("--> txid: #{txid}")
167
+ @log.error("--> adapter: "+ adapter.getName())
168
+ end
169
+
61
170
  return nil
62
171
  end
172
+
63
173
  if prev_op_return != nil && prev_op_return != op_return
174
+ if @log.error?
175
+ @log.error("[BlockchainConnection.getTx] op_return mismatch")
176
+ @log.error("-> txid: #{txid}")
177
+ @log.error("--> txid: #{txid}")
178
+ @log.error("--> adapter: "+ adapter.getName())
179
+ end
180
+
64
181
  return nil
65
182
  end
66
183
 
@@ -75,6 +192,9 @@ module VChainClient
75
192
  "block_timestamp" => prev_block_timestamp,
76
193
  "op_return" => prev_op_return
77
194
  }
195
+
196
+ else
197
+ raise "There are no initialized blockchain_adapters"
78
198
  end
79
199
 
80
200
  return nil
@@ -2,36 +2,134 @@ module VChainClient
2
2
 
3
3
  class BlockcypherBlockchainAdapter < VChainClient::BlockchainAdapter
4
4
 
5
+ @log = nil
6
+
5
7
  @api_token = nil
6
8
 
7
9
  def initialize(api_token)
8
10
  @api_token = api_token
11
+
12
+ @log = Log4r::Logger["vchain_client"]
9
13
  end
10
14
 
15
+ def getName()
16
+ return "BlockcypherBlockchainAdapter"
17
+ end
18
+
11
19
  def getTx(txid)
12
20
  url = "https://api.blockcypher.com/v1/btc/main/txs/"
13
21
  url += txid
14
22
  url += "?token="+ @api_token
15
23
  url += "&rand="+ Random.rand(0...999999).to_s
16
24
 
17
- req = RestClient.get(url)
25
+ if @log.debug?
26
+ @log.debug("[Blockcypher.getTx] input:")
27
+ @log.debug("-> txid: #{txid}")
28
+
29
+ @log.debug("[Blockcypher.getTx] will call '#{url}'")
30
+ end
31
+
32
+ req = nil
33
+
34
+ begin
35
+
36
+ req = RestClient.get(url)
37
+
38
+ rescue => e
39
+ if @log.error?
40
+ @log.error("[Blockcypher.getTx] RestClient.get raised exception:")
41
+ @log.error("#{e.class}, #{e.message}")
42
+ @log.error("-> txid: #{txid}")
43
+ @log.error("--> url: #{url}")
44
+ end
45
+
46
+ raise e
47
+ end
48
+
49
+ if req == nil
50
+ if @log.error?
51
+ @log.error("[Blockcypher.getTx] failed to call REST")
52
+ @log.error("-> txid: #{txid}")
53
+ @log.error("--> url: #{url}")
54
+ end
55
+
56
+ return nil
57
+ end
18
58
 
19
59
  if req.code != 200
60
+ if @log.error?
61
+ @log.error("[Blockcypher.getTx] REST call returned "+ req.code.to_s)
62
+ @log.error("-> txid: #{txid}")
63
+ @log.error("--> url: #{url}")
64
+ end
65
+
20
66
  return nil
21
67
  end
22
68
 
69
+ if @log.debug?
70
+ @log.debug("[Blockcypher.getTx] REST call response:")
71
+ @log.debug(req.body)
72
+ end
73
+
23
74
  res = JSON.parse req.body
24
75
 
25
76
  if res != nil
77
+
26
78
  if res.key?("confirmations")
79
+
27
80
  if res["confirmations"] > 5
81
+
28
82
  if res.key?("block_hash")
83
+
29
84
  if res.key?("confirmed")
30
- block_timestamp = DateTime.parse(res["confirmed"]).to_i
31
85
 
32
- op_return = self.getOpReturn(res)
86
+ block_timestamp = nil
87
+
88
+ begin
89
+
90
+ block_timestamp = DateTime.parse(res["confirmed"]).to_i
91
+
92
+ rescue => e
93
+ if @log.error?
94
+ @log.error("[Blockcypher.getTx] DateTime.parse('confirmed').to_i raised exception:")
95
+ @log.error("#{e.class}, #{e.message}")
96
+ @log.error("-> txid: #{txid}")
97
+ @log.error("--> url: #{url}")
98
+ end
99
+
100
+ raise e
101
+ end
102
+
103
+ if block_timestamp == nil
104
+ if @log.error?
105
+ @log.error("[Blockcypher.getTx] failed to convert 'confirmed' field to timestamp")
106
+ @log.error("-> txid: #{txid}")
107
+ @log.error("--> url: #{url}")
108
+ end
109
+
110
+ return nil
111
+ end
112
+
113
+ op_return = nil
114
+
115
+ begin
116
+
117
+ op_return = self.getOpReturn(res)
118
+
119
+ rescue => e
120
+ if @log.error?
121
+ @log.error("[Blockcypher.getTx] getOpReturn raised exception:")
122
+ @log.error("#{e.class}, #{e.message}")
123
+ @log.error("-> txid: #{txid}")
124
+ @log.error("--> res:")
125
+ @log.error(res)
126
+ end
127
+
128
+ raise e
129
+ end
33
130
 
34
131
  if op_return != nil
132
+
35
133
  prefix = op_return[0..2]
36
134
 
37
135
  if prefix == "VCH"
@@ -43,11 +141,62 @@ module VChainClient
43
141
  "block_timestamp" => block_timestamp,
44
142
  "op_return" => op_return
45
143
  }
144
+
145
+ else
146
+ if @log.error?
147
+ @log.error("[Blockcypher.getTx] wrong prefix '#{prefix}'")
148
+ @log.error("-> txid: #{txid}")
149
+ @log.error("--> res:")
150
+ @log.error(res)
151
+ end
46
152
  end
153
+
154
+ else
155
+ if @log.error?
156
+ @log.error("[Blockcypher.getTx] failed to get OP_RETURN")
157
+ @log.error("-> txid: #{txid}")
158
+ @log.error("--> res:")
159
+ @log.error(res)
160
+ end
47
161
  end
162
+
163
+ else
164
+ if @log.error?
165
+ @log.error("[Blockcypher.getTx] no 'confirmed' field in response")
166
+ @log.error("-> txid: #{txid}")
167
+ @log.error("--> url: #{url}")
168
+ end
48
169
  end
170
+
171
+ else
172
+ if @log.error?
173
+ @log.error("[Blockcypher.getTx] no 'block_hash' field in response")
174
+ @log.error("-> txid: #{txid}")
175
+ @log.error("--> url: #{url}")
176
+ end
49
177
  end
178
+
179
+ else
180
+ if @log.error?
181
+ @log.error("[Blockcypher.getTx] less than 6 confirmations")
182
+ @log.error("-> txid: #{txid}")
183
+ @log.error("--> url: #{url}")
184
+ end
50
185
  end
186
+
187
+ else
188
+ if @log.error?
189
+ @log.error("[Blockcypher.getTx] no 'confirmations' field")
190
+ @log.error("-> txid: #{txid}")
191
+ @log.error("--> url: #{url}")
192
+ end
193
+ end
194
+
195
+ else
196
+ if @log.error?
197
+ @log.error("[Blockcypher.getTx] REST call - empty response")
198
+ @log.error("-> txid: #{txid}")
199
+ @log.error("--> url: #{url}")
51
200
  end
52
201
  end
53
202