onchain 0.3.2 → 0.4.2

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: cf1db897648edb5c34f592d6c7e25d3cd00174bc
4
- data.tar.gz: 6b20b0e29e7790a0a2dc2162f20c7ea83a338816
3
+ metadata.gz: 0e90d6f43622f2013449f0c645899416c69cda45
4
+ data.tar.gz: 0d2e9ee4ab58da945e8f8cb47c70659174a765bc
5
5
  SHA512:
6
- metadata.gz: e03cc4415f9e334183726836f1335cfbcc9300863a3813131d7e2df575e8fb25643a7e3a3f99346e77e0a6217174e7ca773f50bc9746db9f166d640c53b68923
7
- data.tar.gz: 3f460ca76845d001d3fa53d80f217a7c857b35c95cba365a953f9548fd87ce1e0060516b456f921139d862ddf3701e8b39fe15406857a6c0138d8c16e8e32c02
6
+ metadata.gz: a86aac2c975f70495a05579fed758f0f8555cc05d40edbe093168e0a451ee19b82f47564c45e4d2d655004494eaa6b44f19a2dcdcfc743405bc21ca19caaa3bd
7
+ data.tar.gz: d6935006cc73b8f8997d47a200d4dfe943125472f076c1774969f6e46b6cc1961461c79328c4c7860586adf7a1d3bbc579258f7a8ce04a8fcebf7374becb9572
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ *.rbc
3
+ .DS_Store
4
+ .bundle
5
+ .rvmrc
6
+ .ruby-version
7
+ .yardoc
8
+ .rake_tasks~
9
+ Gemfile.lock
10
+ coverage/*
11
+ doc/*
12
+ log/*
13
+ pkg/*
14
+ .idea/*
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ onchain-gem
2
+ ===========
3
+
4
+ Ruby gem to access 3rd party block chain API and unchain services.
@@ -0,0 +1,3 @@
1
+ module Onchain
2
+ VERSION = "0.4.2"
3
+ end
data/lib/onchain.rb ADDED
@@ -0,0 +1,289 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ class OnChain
5
+ class << self
6
+
7
+ BALANCE_CACHE_FOR = 120
8
+ API_CACHE_FOR = 60
9
+
10
+ @@cache = {}
11
+
12
+ def cache_write(key, data, max_age=0)
13
+ @@cache[key] = [Time.now, data, max_age]
14
+ end
15
+
16
+ def cache_read(key)
17
+ # if the API URL exists as a key in cache, we just return it
18
+ # we also make sure the data is fresh
19
+ if @@cache.has_key? key
20
+ return @@cache[key][1] if Time.now-@@cache[key][0] < @@cache[key][2]
21
+ end
22
+ end
23
+
24
+
25
+ def get_all_balances(addresses)
26
+
27
+ if ! blockr_down?
28
+ bal = blockr_get_all_balances(addresses)
29
+ return bal
30
+ end
31
+
32
+ if ! blockchain_down?
33
+ bal = blockinfo_get_all_balances(addresses)
34
+ return bal
35
+ end
36
+ end
37
+
38
+ def get_balance(address)
39
+
40
+ # These guys make 300k per month so hammer them first.
41
+ if ! blockchain_down?
42
+ bal = blockinfo_balance(address)
43
+ if ! bal.instance_of? String
44
+ return bal
45
+ end
46
+ end
47
+
48
+ # Looks like blockchain is down, let's try blockr
49
+ if ! blockr_down?
50
+ bal = blockr_balance(address)
51
+ if ! bal.instance_of? String
52
+ return bal
53
+ end
54
+ end
55
+
56
+ # OK I give up.
57
+ 'Balance could not be retrieved'
58
+ end
59
+
60
+ def send_tx(tx_hex)
61
+ #payload = { :tx => tx_hex }
62
+ #HTTParty.post('http://blockchain.info/pushtx', {:body => payload})
63
+
64
+ # Blockchain doesn't support multi sig, so only use blockr
65
+ uri = URI.parse("http://btc.blockr.io/api/v1/tx/push")
66
+ http = Net::HTTP.new(uri.host, uri.port)
67
+
68
+ request = Net::HTTP::Post.new(uri.request_uri)
69
+ request.body = '{"hex":"' + tx_hex + '"}'
70
+ response = http.request(request)
71
+ return response
72
+ end
73
+
74
+ def get_history
75
+ return []
76
+ end
77
+
78
+ def get_unspent_outs(address)
79
+
80
+
81
+ # Looks like blockchain is down, let's try blockr
82
+ if ! blockr_down?
83
+ return blockr_unspent(address)
84
+ end
85
+
86
+ if ! blockchain_down?
87
+ return blockinfo_unspent(address)
88
+ end
89
+
90
+ # OK I give up.
91
+ 'Unspent outputs could not be retrieved'
92
+
93
+ end
94
+
95
+ def blockchain_is_down
96
+ cache_write(:blockchainapi, 'it is down', 60)
97
+ end
98
+
99
+ def blockchain_down?
100
+ if cache_read(:blockchainapi) != nil
101
+ return true
102
+ end
103
+ return false
104
+ end
105
+
106
+ def blockr_is_down
107
+ cache_write(:blockrapi, 'it is down', 60)
108
+ end
109
+
110
+ def blockr_down?
111
+ if cache_read(:blockrapi) != nil
112
+ return true
113
+ end
114
+ return false
115
+ end
116
+
117
+ def blockinfo_get_all_balances(addresses)
118
+ begin
119
+ base = "https://blockchain.info/multiaddr?&simple=true&active="
120
+
121
+ addresses.each do |address|
122
+ base = base + address + '|'
123
+ end
124
+
125
+ json = fetch_response(URI::encode(base))
126
+
127
+ addresses.each do |address|
128
+ bal = json[address]['final_balance'] / 100000000.0
129
+ cache_write(address, bal, BALANCE_CACHE_FOR)
130
+ end
131
+
132
+ rescue
133
+ 'Balance could not be retrieved'
134
+ end
135
+ end
136
+
137
+ def blockinfo_unspent(address)
138
+ begin
139
+ base_url = "http://blockchain.info/unspent?active=#{address}"
140
+ json = fetch_response(base_url, true)
141
+
142
+ unspent = []
143
+
144
+ json['unspent_outputs'].each do |data|
145
+ line = []
146
+ line << reverse_blockchain_tx(data['tx_hash'])
147
+ line << data['tx_output_n']
148
+ line << data['script']
149
+ line << data['value']
150
+ unspent << line
151
+ end
152
+
153
+ return unspent
154
+ rescue Exception => e
155
+ puts e.to_s
156
+ 'Unspent outputs could not be retrieved'
157
+ end
158
+ end
159
+
160
+ def blockinfo_balance(address)
161
+ begin
162
+ if cache_read(address) == nil
163
+ puts "cache is empty"
164
+ json = block_chain('address', address, "&limit=0")
165
+ if json.key?('final_balance')
166
+ bal = json['final_balance'] / 100000000.0
167
+ cache_write(address, bal, BALANCE_CACHE_FOR)
168
+ else
169
+ cache_write(address, 'Error', BALANCE_CACHE_FOR)
170
+ end
171
+ end
172
+ bal = cache_read(address)
173
+ if bal.class == Fixnum
174
+ bal = bal.to_f
175
+ end
176
+ return bal
177
+ rescue
178
+ 'Balance could not be retrieved'
179
+ end
180
+ end
181
+
182
+ def blockr_unspent(address)
183
+ begin
184
+ base_url = "http://btc.blockr.io/api/v1/address/unspent/#{address}"
185
+ json = fetch_response(base_url, true)
186
+
187
+ unspent = []
188
+
189
+ json['data']['unspent'].each do |data|
190
+ line = []
191
+ line << data['tx']
192
+ line << data['n']
193
+ line << data['script']
194
+ line << (data['amount'].to_f * 100000000).to_i
195
+ unspent << line
196
+ end
197
+
198
+ return unspent
199
+ rescue Exception => e
200
+ puts e.to_s
201
+ 'Unspent outputs could not be retrieved'
202
+ end
203
+ end
204
+
205
+ def blockr_get_all_balances(addresses)
206
+ begin
207
+ base = "https://blockr.io/api/v1/address/balance/"
208
+
209
+ addresses.each do |address|
210
+ base = base + address + ','
211
+ end
212
+
213
+ json = fetch_response(URI::encode(base))
214
+
215
+ json['data'].each do |data|
216
+ bal = data['balance']
217
+ addr = data['address']
218
+ cache_write(addr, bal, BALANCE_CACHE_FOR)
219
+ end
220
+
221
+ rescue
222
+ 'Balance could not be retrieved'
223
+ end
224
+ end
225
+
226
+ def blockr_balance(address)
227
+ begin
228
+ if cache_read(address) == nil
229
+ json = blockr('address/balance', address)
230
+ if json.key?('data')
231
+ bal = json['data']['balance'].to_f
232
+ cache_write(address, bal, BALANCE_CACHE_FOR)
233
+ else
234
+ cache_write(address, 'Error', BALANCE_CACHE_FOR)
235
+ end
236
+ end
237
+ return cache_read(address)
238
+ rescue Exception => e
239
+ puts e
240
+ 'Balance could not be retrieved'
241
+ end
242
+ end
243
+
244
+ def blockr(cmd, address, params = "")
245
+ if ! blockr_down?
246
+ begin
247
+ base_url = "http://blockr.io/api/v1/#{cmd}/#{address}" + params
248
+ fetch_response(base_url, true)
249
+ rescue
250
+ blockr_is_down
251
+ end
252
+ end
253
+ end
254
+
255
+ def block_chain(cmd, address, params = "")
256
+ if ! blockchain_down?
257
+ begin
258
+ base_url = "http://blockchain.info/#{cmd}/#{address}?format=json" + params
259
+
260
+ puts base_url
261
+ fetch_response(base_url, true)
262
+ rescue
263
+ blockchain_is_down
264
+ end
265
+ end
266
+ end
267
+
268
+ def fetch_response(url, do_json=true)
269
+ resp = Net::HTTP.get_response(URI.parse(url))
270
+ data = resp.body
271
+
272
+ if do_json
273
+ result = JSON.parse(data)
274
+ else
275
+ data
276
+ end
277
+ end
278
+
279
+ def reverse_blockchain_tx(hash)
280
+ bytes = hash.scan(/../).map { |x| x.hex.chr }.join
281
+
282
+ bytes = bytes.reverse
283
+
284
+ return hash.scan(/../).reverse.join
285
+ end
286
+
287
+
288
+ end
289
+ end
data/onchain.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/onchain/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Ian Purton"]
6
+ gem.email = ["ian@onchain.com"]
7
+ gem.summary = %q{Ruby wrapper for various 3rd-party bitcoin APIs}
8
+ gem.description = %q{Call 3rd party API's but also switch API's if a 3rd party is down}
9
+ gem.homepage = "https://github.com/onchain/onchain-gem"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "onchain"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Onchain::VERSION
17
+
18
+ %w{rspec vcr ir_b guard-rspec webmock}.each do |gem_library|
19
+ gem.add_development_dependency gem_library
20
+ end
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onchain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Purton
@@ -86,7 +86,12 @@ email:
86
86
  executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
- files: []
89
+ files:
90
+ - ".gitignore"
91
+ - README.md
92
+ - lib/onchain.rb
93
+ - lib/onchain/version.rb
94
+ - onchain.gemspec
90
95
  homepage: https://github.com/onchain/onchain-gem
91
96
  licenses: []
92
97
  metadata: {}