Class: OnChain::BlockChain
- Inherits:
-
Object
- Object
- OnChain::BlockChain
- Defined in:
- lib/onchain/providers/chaincom_api.rb,
lib/onchain/block_chain.rb,
lib/onchain/providers/blockr_api.rb,
lib/onchain/providers/blockchaininfo_api.rb
Overview
No longer works as Chain.com pivoted into a blockchain company.
Constant Summary collapse
- ALL_SUPPLIERS =
[ :blockr, :blockinfo ]
- BALANCE_CACHE_FOR =
120- API_CACHE_FOR =
60- SERVICE_DOWN_FOR =
60- @@cache =
{}
Class Method Summary collapse
- .block_chain(cmd, address, params = "") ⇒ Object
- .blockinfo_address_history(address) ⇒ Object
- .blockinfo_get_address_info(address) ⇒ Object
- .blockinfo_get_all_balances(addresses) ⇒ Object
- .blockinfo_get_balance(address) ⇒ Object
- .blockinfo_get_history_for_addresses(addresses) ⇒ Object
- .blockinfo_get_unspent_outs(address) ⇒ Object
- .blockinfo_parse_address_tx(address, json) ⇒ Object
- .blockr(cmd, address, params = "") ⇒ Object
- .blockr_get_address_info(address) ⇒ Object
- .blockr_get_all_balances(addresses) ⇒ Object
- .blockr_get_balance(address) ⇒ Object
- .blockr_get_transactions(address) ⇒ Object
- .blockr_get_unspent_outs(address) ⇒ Object
- .blockr_send_tx(tx_hex) ⇒ Object
- .cache_read(key) ⇒ Object
- .cache_write(key, data, max_age = 0) ⇒ Object
- .chaincom_address_history(address) ⇒ Object
- .chaincom_get_all_balances(addresses) ⇒ Object
- .chaincom_get_balance(address) ⇒ Object
- .chaincom_get_history_for_addresses(addresses) ⇒ Object
- .chaincom_get_transactions(address) ⇒ Object
- .chaincom_get_unspent_outs(address) ⇒ Object
- .chaincom_parse_address_tx(addresses, txs) ⇒ Object
- .chaincom_send_tx(tx_hex) ⇒ Object
- .fetch_response(url, do_json = true) ⇒ Object
- .get_available_suppliers(method_name) ⇒ Object
- .get_balance_satoshi(address) ⇒ Object
-
.get_uncached_addresses(addresses) ⇒ Object
Given a list of addresses, return those that don’t have balances in the cahce.
- .get_unspent_for_amount(addresses, amount_in_satoshi) ⇒ Object
- .method_missing(method_name, *args, &block) ⇒ Object
- .reverse_blockchain_tx(hash) ⇒ Object
Class Method Details
.block_chain(cmd, address, params = "") ⇒ Object
130 131 132 133 134 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 130 def block_chain(cmd, address, params = "") base_url = "https://blockchain.info/#{cmd}/#{address}?format=json" + params fetch_response(base_url, true) end |
.blockinfo_address_history(address) ⇒ Object
16 17 18 19 20 21 22 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 16 def blockinfo_address_history(address) base_url = "https://blockchain.info/address/#{address}?format=json" json = fetch_response(base_url, true) blockinfo_parse_address_tx(address, json) end |
.blockinfo_get_address_info(address) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 62 def blockinfo_get_address_info(address) base = "https://blockchain.info/multiaddr?&simple=true&active=" + address json = fetch_response(URI::encode(base)) return { received: json[address]['total_received'], balance: json[address]['final_balance'], confirmed: json[address]['final_balance'] } end |
.blockinfo_get_all_balances(addresses) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 74 def blockinfo_get_all_balances(addresses) base = "https://blockchain.info/multiaddr?&simple=true&active=" addr = get_uncached_addresses(addresses) if addr.length == 0 return end addr.each do |address| base = base + address + '|' end json = fetch_response(URI::encode(base)) addresses.each do |address| bal = json[address]['final_balance'] / 100000000.0 cache_write(address, bal, BALANCE_CACHE_FOR) end end |
.blockinfo_get_balance(address) ⇒ Object
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 113 def blockinfo_get_balance(address) if cache_read(address) == nil json = block_chain('address', address, "&limit=0") if json.key?('final_balance') bal = json['final_balance'] / 100000000.0 cache_write(address, bal, BALANCE_CACHE_FOR) else cache_write(address, 'Error', BALANCE_CACHE_FOR) end end bal = cache_read(address) if bal.class == Fixnum bal = bal.to_f end return bal end |
.blockinfo_get_history_for_addresses(addresses) ⇒ Object
5 6 7 8 9 10 11 12 13 14 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 5 def blockinfo_get_history_for_addresses(addresses) history = [] addresses.each do |address| res = blockinfo_address_history(address) res.each do |r| history << r end end return history end |
.blockinfo_get_unspent_outs(address) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 95 def blockinfo_get_unspent_outs(address) base_url = "https://blockchain.info/unspent?active=#{address}" json = fetch_response(base_url, true) unspent = [] json['unspent_outputs'].each do |data| line = [] line << reverse_blockchain_tx(data['tx_hash']) line << data['tx_output_n'] line << data['script'] line << data['value'] unspent << line end return unspent end |
.blockinfo_parse_address_tx(address, json) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 24 def blockinfo_parse_address_tx(address, json) hist = [] if json.key?('txs') txs = json['txs'] txs.each do |tx| row = {} row[:time] = tx["time"] row[:addr] = {} row[:outs] = {} inputs = tx['inputs'] val = 0 recv = "Y" inputs.each do |input| row[:addr][input["prev_out"]["addr"]] = input["prev_out"]["addr"] if input["prev_out"]["addr"] == address recv = "N" end end tx["out"].each do |out| row[:outs][out["addr"]] = out["addr"] if recv == "Y" and out["addr"] == address val = val + out["value"].to_f / 100000000.0 elsif recv == "N" and out["addr"] != address val = val + out["value"].to_f / 100000000.0 end end row[:total] = val row[:recv] = recv hist << row end return hist else 'Error' end return hist end |
.blockr(cmd, address, params = "") ⇒ Object
105 106 107 108 109 110 |
# File 'lib/onchain/providers/blockr_api.rb', line 105 def blockr(cmd, address, params = "") base_url = "http://blockr.io/api/v1/#{cmd}/#{address}" + params fetch_response(base_url, true) end |
.blockr_get_address_info(address) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/onchain/providers/blockr_api.rb', line 38 def blockr_get_address_info(address) json = blockr('address/balance', address) return { received: json[address]['total_received'], balance: json[address]['final_balance'], confirmed: json[address]['final_balance'] } end |
.blockr_get_all_balances(addresses) ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/onchain/providers/blockr_api.rb', line 82 def blockr_get_all_balances(addresses) addr = get_uncached_addresses(addresses) if addr.length == 0 return end base = "https://blockr.io/api/v1/address/balance/" addr.each do |address| base = base + address + ',' end json = fetch_response(URI::encode(base)) json['data'].each do |data| bal = data['balance'].to_f addr = data['address'] cache_write(addr, bal, BALANCE_CACHE_FOR) end end |
.blockr_get_balance(address) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/onchain/providers/blockr_api.rb', line 25 def blockr_get_balance(address) if cache_read(address) == nil json = blockr('address/balance', address) if json.key?('data') bal = json['data']['balance'].to_f cache_write(address, bal, BALANCE_CACHE_FOR) else cache_write(address, 'Error', BALANCE_CACHE_FOR) end end return cache_read(address) end |
.blockr_get_transactions(address) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/onchain/providers/blockr_api.rb', line 48 def blockr_get_transactions(address) base_url = "http://btc.blockr.io/api/v1/address/txs/#{address}" json = fetch_response(base_url, true) unspent = [] json['data']['txs'].each do |data| line = [] line << data['tx'] line << data['amount'].to_f unspent << line end return unspent end |
.blockr_get_unspent_outs(address) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/onchain/providers/blockr_api.rb', line 64 def blockr_get_unspent_outs(address) base_url = "http://btc.blockr.io/api/v1/address/unspent/#{address}" json = fetch_response(base_url, true) unspent = [] json['data']['unspent'].each do |data| line = [] line << data['tx'] line << data['n'] line << data['script'] line << (data['amount'].to_f * 100000000).to_i unspent << line end return unspent end |
.blockr_send_tx(tx_hex) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/onchain/providers/blockr_api.rb', line 4 def blockr_send_tx(tx_hex) uri = URI.parse("http://btc.blockr.io/api/v1/tx/push") http = Net::HTTP.new(uri.host, uri.port) request = Net::HTTP::Post.new(uri.request_uri) request.body = '{"hex":"' + tx_hex + '"}' response = http.request(request) res = JSON.parse(response.body) mess = res["message"] stat = res["status"] if stat == 'fail' stat = 'failure' end tx_hash = res["data"] ret = "{\"status\":\"#{stat}\",\"data\":\"#{tx_hash}\",\"code\":200,\"message\":\"#{mess}\"}" return JSON.parse(ret) end |
.cache_read(key) ⇒ Object
153 154 155 156 157 158 159 |
# File 'lib/onchain/block_chain.rb', line 153 def cache_read(key) # if the API URL exists as a key in cache, we just return it # we also make sure the data is fresh if @@cache.has_key? key return @@cache[key][1] if Time.now-@@cache[key][0] < @@cache[key][2] end end |
.cache_write(key, data, max_age = 0) ⇒ Object
149 150 151 |
# File 'lib/onchain/block_chain.rb', line 149 def cache_write(key, data, max_age=0) @@cache[key] = [Time.now, data, max_age] end |
.chaincom_address_history(address) ⇒ Object
15 16 17 18 19 20 |
# File 'lib/onchain/providers/chaincom_api.rb', line 15 def chaincom_address_history(address) txs = Chain.get_address_transactions(address) return chaincom_parse_address_tx([address], txs) end |
.chaincom_get_all_balances(addresses) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/onchain/providers/chaincom_api.rb', line 114 def chaincom_get_all_balances(addresses) addr = get_uncached_addresses(addresses) if addr.length == 0 return end res = Chain.get_addresses(addr) if ! res.kind_of?(Array) res = [res] end res.each do |address| bal = address["total"]["balance"] / 100000000.0 cache_write(address["address"], bal, BALANCE_CACHE_FOR) end end |
.chaincom_get_balance(address) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/onchain/providers/chaincom_api.rb', line 67 def chaincom_get_balance(address) if cache_read(address) == nil addr = Chain.get_address(address) if addr.count > 0 bal = addr[0]["total"]["balance"].to_i / 100000000.0 cache_write(address, bal, BALANCE_CACHE_FOR) end end return cache_read(address) end |
.chaincom_get_history_for_addresses(addresses) ⇒ Object
9 10 11 12 13 |
# File 'lib/onchain/providers/chaincom_api.rb', line 9 def chaincom_get_history_for_addresses(addresses) txs = Chain.get_addresses_transactions(addresses) return chaincom_parse_address_tx(addresses, txs) end |
.chaincom_get_transactions(address) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/onchain/providers/chaincom_api.rb', line 80 def chaincom_get_transactions(address) txs = Chain.get_address_transactions(address) unspent = [] txs.each do |data| line = [] line << data['hash'] line << data["outputs"][0]["value"] / 100000000.0 unspent << line end return unspent end |
.chaincom_get_unspent_outs(address) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/onchain/providers/chaincom_api.rb', line 96 def chaincom_get_unspent_outs(address) uns = Chain.get_address_unspents(address) unspent = [] uns.each do |data| line = [] line << data['transaction_hash'] line << data['output_index'] line << data['script_hex'] line << data['value'] unspent << line end return unspent end |
.chaincom_parse_address_tx(addresses, txs) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/onchain/providers/chaincom_api.rb', line 22 def chaincom_parse_address_tx(addresses, txs) hist = [] txs.each do |tx| row = {} row[:time] = Time.parse(tx["block_time"]).to_i row[:addr] = {} row[:outs] = {} inputs = tx['inputs'] val = 0 recv = "Y" inputs.each do |input| row[:addr][input["addresses"][0]] = input["addresses"][0] if addresses.include? input["addresses"][0] recv = "N" end end tx["outputs"].each do |out| row[:outs][out["addresses"][0] ] = out["addresses"][0] if recv == "Y" and addresses.include? out["addresses"][0] val = val + out["value"].to_f / 100000000.0 elsif recv == "N" and addresses.include? out["addresses"][0] val = val + out["value"].to_f / 100000000.0 end end row[:total] = val row[:recv] = recv hist << row end return hist end |
.chaincom_send_tx(tx_hex) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/onchain/providers/chaincom_api.rb', line 54 def chaincom_send_tx(tx_hex) begin tx = Chain.send_transaction(tx_hex) tx_hash = tx["transaction_hash"] ret = "{\"status\":\"success\",\"data\":\"#{tx_hash}\",\"code\":200,\"message\":\"\"}" return JSON.parse(ret) rescue => e ret = "{\"status\":\"failure\",\"data\":\"#{tx_hash}\",\"code\":200,\"message\":\"#{e.to_s}\"}" return JSON.parse(ret) end end |
.fetch_response(url, do_json = true) ⇒ Object
161 162 163 164 165 166 167 168 169 170 |
# File 'lib/onchain/block_chain.rb', line 161 def fetch_response(url, do_json=true) resp = Net::HTTP.get_response(URI.parse(url)) data = resp.body if do_json result = JSON.parse(data) else data end end |
.get_available_suppliers(method_name) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/onchain/block_chain.rb', line 112 def get_available_suppliers(method_name) available = [] ALL_SUPPLIERS.each do |supplier| if cache_read(supplier.to_s) == nil if supplier == :blockinfo and method_name.to_s == 'send_tx' next end if supplier == :blockinfo and method_name.to_s == 'get_transactions' next end if supplier == :blockr and method_name.to_s == 'address_history' next end if supplier == :blockr and method_name.to_s == 'get_address_info' next end if supplier == :blockr and method_name.to_s == 'get_history_for_addresses' next end available << supplier end end return available end |
.get_balance_satoshi(address) ⇒ Object
108 109 110 |
# File 'lib/onchain/block_chain.rb', line 108 def get_balance_satoshi(address) return (get_balance(address).to_f * 100000000).to_i end |
.get_uncached_addresses(addresses) ⇒ Object
Given a list of addresses, return those that don’t have balances in the cahce.
67 68 69 70 71 72 73 74 75 |
# File 'lib/onchain/block_chain.rb', line 67 def get_uncached_addresses(addresses) ret = [] addresses.each do |address| if cache_read(address) == nil ret << address end end return ret end |
.get_unspent_for_amount(addresses, amount_in_satoshi) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/onchain/block_chain.rb', line 77 def get_unspent_for_amount(addresses, amount_in_satoshi) unspents = [] indexes = [] amount_so_far = 0 addresses.each_with_index do |address, index| if amount_so_far >= amount_in_satoshi break end unspent_outs = get_unspent_outs(address) unspent_outs.each do |spent| unspents << spent indexes << index amount_so_far = amount_so_far + spent[3].to_i if amount_so_far >= amount_in_satoshi break end end end change = amount_so_far - amount_in_satoshi return unspents, indexes, change end |
.method_missing(method_name, *args, &block) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/onchain/block_chain.rb', line 32 def method_missing (method_name, *args, &block) if ENV['CHAIN-API-KEY-ID'] != nil begin Chain.api_key_id = ENV['CHAIN-API-KEY-ID'] Chain.api_key_secret = ENV['CHAIN-API-KEY-SECRET'] rescue # Had problems setting this so get arou d it. end end get_available_suppliers(method_name).each do |supplier| real_method = "#{supplier.to_s}_#{method_name}" begin method = self.method(real_method) begin result = method.call(*args) return result rescue => e2 # We have the method but it errored. Assume # service is down. cache_write(supplier.to_s, 'down', SERVICE_DOWN_FOR) puts e2.to_s end rescue => e puts "there's no method called '#{real_method}'" puts e.backtrace end end end |
.reverse_blockchain_tx(hash) ⇒ Object
136 137 138 139 140 141 142 |
# File 'lib/onchain/providers/blockchaininfo_api.rb', line 136 def reverse_blockchain_tx(hash) bytes = hash.scan(/../).map { |x| x.hex.chr }.join bytes = bytes.reverse return hash.scan(/../).reverse.join end |