Module: Bitbot::UpdateAddresses

Included in:
Plugin
Defined in:
lib/bitbot/plugin/update_addresses.rb

Instance Method Summary collapse

Instance Method Details

#cache_file_pathObject



2
3
4
# File 'lib/bitbot/plugin/update_addresses.rb', line 2

def cache_file_path
  File.join(config['data']['path'], "cached_addresses.yml")
end

#on_update_addresses(event = nil) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
53
54
55
56
57
# File 'lib/bitbot/plugin/update_addresses.rb', line 6

def on_update_addresses(event = nil)
  if cached_addresses.nil?
    # Load from the cache, if available, on first load
    self.cached_addresses = YAML.load(File.read(cache_file_path)) rescue nil
  end

  # Updates the cached map of depositing addresses. 
  new_addresses = {}
  all_addresses = []

  addresses = blockchain.get_addresses_in_wallet()
  addresses.each do |address|
    all_addresses << address["address"]
    next unless address["label"] =~ /^\d+$/

    user_id = address["label"].to_i

    new_addresses[user_id] = address

    # We set a flag on the address saying we need to get the
    # confirmed balance IF the previous entry has the flag, OR
    # the address is new OR if the balance does not equal the
    # previous balance. We only clear the field when the balance
    # equals the confirmed balance.
    address["need_confirmed_balance"] = @cached_addresses[user_id]["need_confirmed_balance"] rescue true
    if address["balance"] != (@cached_addresses[user_id]["balance"] rescue nil)
      address["need_confirmed_balance"] = true
    end
  end

  # Now go through new addresses, performing any confirmation checks
  # for flagged ones.
  new_addresses.each do |user_id, address|
    if address["need_confirmed_balance"]
      balance = blockchain.get_balance_for_address(address["address"])
      address["confirmed_balance"] = balance

      if address["confirmed_balance"] == address["balance"]
        address["need_confirmed_balance"] = false
      end

      # Process any transactions for this address
      process_new_transactions_for_address(address, user_id, all_addresses)
    end
  end

  # Thread-safe? Sure, why not.
  self.cached_addresses = new_addresses

  # Cache them on disk for faster startups
  File.write(cache_file_path, YAML.dump(new_addresses))
end

#process_new_transactions_for_address(address, user_id, all_addresses) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
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
107
108
109
110
# File 'lib/bitbot/plugin/update_addresses.rb', line 59

def process_new_transactions_for_address(address, user_id, all_addresses)
  existing_transactions = {}
  db.get_incoming_transaction_ids.each do |txid|
    existing_transactions[txid] = true
  end

  response = blockchain.get_details_for_address(address["address"])

  username = db.get_username_for_user_id(user_id)

  response["txs"].each do |tx|
    # Skip ones we already have in the database
    next if existing_transactions[tx["hash"]]

    # Skip any transactions that have an existing bitbot address
    # as an input
    if tx["inputs"].any? {|input| all_addresses.include? input["prev_out"]["addr"] }
      debug "Skipping tx with bitbot input address: #{tx["hash"]}"
      next
    end

    # find the total amount for this address
    amount = 0
    tx["out"].each do |out|
      if out["addr"] == address["address"]
        amount += out["value"]
      end
    end

    # Skip unless it's in a block (>=1 confirmation)
    if !tx["block_height"] || tx["block_height"] == 0
      # TODO: only tell them this one time.
      if ircuser = user_with_username(username)
        ircuser.msg "Waiting for confirmation of transaction of " +
          satoshi_with_usd(amount) +
          " in transaction #{tx["hash"].irc(:grey)}"
      end
      next
    end

    # There is a unique constraint on incoming_transaction, so this
    # will fail if for some reason we try to add it again.
    if db.create_transaction_from_deposit(user_id, amount, tx["hash"])
      # Notify the depositor, if they're around
      if ircuser = user_with_username(username)
        ircuser.msg "Received deposit of " +
          satoshi_with_usd(amount) + ". Current balance is " +
          satoshi_with_usd(db.get_balance_for_user_id(user_id)) + "."
      end
    end
  end
end