class Pochette::Backends::BlockchainInfo

Attributes

api_key[RW]

Public Class Methods

new(key = nil) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 10
def initialize(key = nil)
  self.api_key = key
end

Public Instance Methods

balances_for(addresses, confirmations) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 29
def balances_for(addresses, confirmations)
  json = get_json("multiaddr", {active: addresses.join('|'), format: 'json'})
  result = {}
  json['addresses'].collect do |a|
    address = a['address']
    sent = get_json("q/getsentbyaddress/#{address}",
      {confirmations: confirmations, format: 'json'})
    received = get_json("q/getreceivedbyaddress/#{address}",
      {confirmations: confirmations, format: 'json'})
    result[address] = [
      sat(received), sat(sent), sat(received - sent),
      sat(a['total_received']), sat(a['total_sent']), sat(a['final_balance'])]
  end
  result
end
block_height() click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 91
def block_height
  get_json("latestblock", {format: 'json'})['height'].to_i
end
get_json(path, params={}) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 103
def get_json(path, params={})
  params['api_code'] = api_key if api_key
  query = params.empty? ? '' : "?#{params.to_query}"
  retries = 30
  begin
    raw_response = open("https://blockchain.info/#{path}#{query}").read
    sleep cooldown
    Oj.load(raw_response)
  rescue OpenURI::HTTPError => e
    raise if retries < 0 || e.message.to_i != 429
    retries -= 1
    sleep (cooldown * 5)
    retry
  end
end
incoming_for(addresses, min_date) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 49
def incoming_for(addresses, min_date)
  return unless latest_block = block_height
  addresses.in_groups_of(50, false).collect do |group|
    incoming_for_helper(group, latest_block)
  end.flatten(1)
end
incoming_for_helper(addresses, latest_block) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 56
def incoming_for_helper(addresses, latest_block)
  json = get_json("multiaddr", {active: addresses.join('|'), format: 'json'})

  json['txs'].collect do |transaction|
    transaction['out'].collect do |out|
      next unless addresses.include? out['addr']
      confirmations = latest_block - transaction['block_height'].to_i
      senders = transaction['inputs'].collect{ |i| i['prev_out']['addr'] }.join(',')
      [ out['value'].to_d, out['addr'], transaction['hash'], confirmations, out['n'], senders ]
    end.compact
  end.flatten(1)
end
list_transactions(txids) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 69
def list_transactions(txids)
  return nil if txids.empty?
  txids.collect do |txid|
    tx = get_json("rawtx/#{txid}", {format: 'json'})
    inputs = tx['inputs'].collect do |i|
      prevhash = get_json("rawtx/#{i['prev_out']['tx_index']}", {format: 'json'})['hash']
      { prev_hash: prevhash,
        prev_index: i['prev_out']['n'],
        sequence: i['sequence'],
        script_sig: i['script']
      }
    end

    outputs = tx['out'].collect do |o|
      { amount: o['value'].to_i, script_pubkey: o['script'] }
    end

    { hash: tx['hash'], version: tx['ver'], lock_time: tx['lock_time'],
      inputs: inputs, bin_outputs: outputs}
  end
end
list_unspent(addresses) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 14
def list_unspent(addresses)
  json = get_json("unspent", {active: addresses.join('|'), format: 'json'})
  json['unspent_outputs'].collect do |utxo|
    address = Bitcoin::Script.new(utxo['script'].htb).get_address
    [address, utxo['tx_hash_big_endian'], utxo['tx_output_n'].to_i, utxo['value'], utxo['script']]
  end
rescue OpenURI::HTTPError => e
  # Blockchain.info returns 500 when there are no unspent outputs
  if e.io.read == "No free outputs to spend"
    return []
  else
    raise
  end
end
propagate(hex) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 95
def propagate(hex)
  uri = URI.parse("https://blockchain.info/pushtx")
  params = { "tx" => hex }
  params['api_code'] = api_key if api_key
  response = Net::HTTP.post_form(uri, params)
  raise StandardError.new(response) if response.code.to_i != 200
end
sat(x) click to toggle source
# File lib/pochette/backends/blockchain_info.rb, line 45
def sat(x)
  x.to_d / 1_0000_0000
end