|
@@ -1,186 +1,194 @@
|
1
|
|
-<?
|
2
|
|
-class DonationsBitcoin {
|
3
|
|
- /**
|
4
|
|
- * Ask bitcoind for a list of all addresses that have received bitcoins
|
5
|
|
- *
|
6
|
|
- * @return array (BitcoinAddress => Amount, ...)
|
7
|
|
- */
|
8
|
|
- public static function get_received() {
|
9
|
|
- if (defined('BITCOIN_RPC_URL')) {
|
10
|
|
- $Donations = BitcoinRpc::listreceivedbyaddress();
|
11
|
|
- }
|
12
|
|
- if (empty($Donations)) {
|
13
|
|
- return [];
|
14
|
|
- }
|
15
|
|
- $BTCUsers = [];
|
16
|
|
- foreach ($Donations as $Account) {
|
17
|
|
- $BTCUsers[$Account->address] = $Account->amount;
|
|
1
|
+<?php
|
|
2
|
+class DonationsBitcoin
|
|
3
|
+{
|
|
4
|
+ /**
|
|
5
|
+ * Ask bitcoind for a list of all addresses that have received bitcoins
|
|
6
|
+ *
|
|
7
|
+ * @return array (BitcoinAddress => Amount, ...)
|
|
8
|
+ */
|
|
9
|
+ public static function get_received()
|
|
10
|
+ {
|
|
11
|
+ if (defined('BITCOIN_RPC_URL')) {
|
|
12
|
+ $Donations = BitcoinRpc::listreceivedbyaddress();
|
|
13
|
+ }
|
|
14
|
+ if (empty($Donations)) {
|
|
15
|
+ return [];
|
|
16
|
+ }
|
|
17
|
+ $BTCUsers = [];
|
|
18
|
+ foreach ($Donations as $Account) {
|
|
19
|
+ $BTCUsers[$Account->address] = $Account->amount;
|
|
20
|
+ }
|
|
21
|
+ return $BTCUsers;
|
18
|
22
|
}
|
19
|
|
- return $BTCUsers;
|
20
|
|
- }
|
21
|
23
|
|
22
|
|
- /**
|
23
|
|
- * Ask bitcoind for the current account balance
|
24
|
|
- *
|
25
|
|
- * @return float balance
|
26
|
|
- */
|
27
|
|
- public static function get_balance() {
|
28
|
|
- if (defined('BITCOIN_RPC_URL')) {
|
29
|
|
- return BitcoinRpc::getbalance();
|
|
24
|
+ /**
|
|
25
|
+ * Ask bitcoind for the current account balance
|
|
26
|
+ *
|
|
27
|
+ * @return float balance
|
|
28
|
+ */
|
|
29
|
+ public static function get_balance()
|
|
30
|
+ {
|
|
31
|
+ if (defined('BITCOIN_RPC_URL')) {
|
|
32
|
+ return BitcoinRpc::getbalance();
|
|
33
|
+ }
|
30
|
34
|
}
|
31
|
|
- }
|
32
|
35
|
|
33
|
|
- /**
|
34
|
|
- * Get a user's existing bitcoin address or generate a new one
|
35
|
|
- *
|
36
|
|
- * @param int $UserID
|
37
|
|
- * @param bool $GenAddress whether to create a new address if it doesn't exist
|
38
|
|
- * @return false if no address exists and $GenAddress is false
|
39
|
|
- * string bitcoin address otherwise
|
40
|
|
- */
|
41
|
|
- public static function get_address($UserID, $GenAddress = false) {
|
42
|
|
- $UserID = (int)$UserID;
|
43
|
|
- $QueryID = G::$DB->get_query_id();
|
44
|
|
- G::$DB->query("
|
|
36
|
+ /**
|
|
37
|
+ * Get a user's existing bitcoin address or generate a new one
|
|
38
|
+ *
|
|
39
|
+ * @param int $UserID
|
|
40
|
+ * @param bool $GenAddress whether to create a new address if it doesn't exist
|
|
41
|
+ * @return false if no address exists and $GenAddress is false
|
|
42
|
+ * string bitcoin address otherwise
|
|
43
|
+ */
|
|
44
|
+ public static function get_address($UserID, $GenAddress = false)
|
|
45
|
+ {
|
|
46
|
+ $UserID = (int)$UserID;
|
|
47
|
+ $QueryID = G::$DB->get_query_id();
|
|
48
|
+ G::$DB->query("
|
45
|
49
|
SELECT BitcoinAddress
|
46
|
50
|
FROM users_info
|
47
|
51
|
WHERE UserID = '$UserID'");
|
48
|
|
- list($Addr) = G::$DB->next_record();
|
49
|
|
- G::$DB->set_query_id($QueryID);
|
|
52
|
+ list($Addr) = G::$DB->next_record();
|
|
53
|
+ G::$DB->set_query_id($QueryID);
|
50
|
54
|
|
51
|
|
- if (!empty($Addr)) {
|
52
|
|
- return $Addr;
|
53
|
|
- } elseif ($GenAddress) {
|
54
|
|
- if (defined('BITCOIN_RPC_URL')) {
|
55
|
|
- $NewAddr = BitcoinRpc::getnewaddress();
|
56
|
|
- }
|
57
|
|
- if (empty($NewAddr)) {
|
58
|
|
- error(0);
|
59
|
|
- }
|
60
|
|
- $QueryID = G::$DB->get_query_id();
|
61
|
|
- G::$DB->query("
|
|
55
|
+ if (!empty($Addr)) {
|
|
56
|
+ return $Addr;
|
|
57
|
+ } elseif ($GenAddress) {
|
|
58
|
+ if (defined('BITCOIN_RPC_URL')) {
|
|
59
|
+ $NewAddr = BitcoinRpc::getnewaddress();
|
|
60
|
+ }
|
|
61
|
+ if (empty($NewAddr)) {
|
|
62
|
+ error(0);
|
|
63
|
+ }
|
|
64
|
+ $QueryID = G::$DB->get_query_id();
|
|
65
|
+ G::$DB->query("
|
62
|
66
|
UPDATE users_info
|
63
|
67
|
SET BitcoinAddress = '".db_string($NewAddr)."'
|
64
|
68
|
WHERE UserID = '$UserID'
|
65
|
69
|
AND BitcoinAddress IS NULL");
|
66
|
|
- G::$DB->set_query_id($QueryID);
|
67
|
|
- return $NewAddr;
|
68
|
|
- } else {
|
69
|
|
- return false;
|
|
70
|
+ G::$DB->set_query_id($QueryID);
|
|
71
|
+ return $NewAddr;
|
|
72
|
+ } else {
|
|
73
|
+ return false;
|
|
74
|
+ }
|
70
|
75
|
}
|
71
|
|
- }
|
72
|
76
|
|
73
|
|
- /**
|
74
|
|
- * Ask bitcoind for the total amount of bitcoins received
|
75
|
|
- *
|
76
|
|
- * @return float amount
|
77
|
|
- */
|
78
|
|
- public static function get_total_received() {
|
79
|
|
- if (defined('BITCOIN_RPC_URL')) {
|
80
|
|
- $Accounts = BitcoinRpc::listreceivedbyaccount();
|
81
|
|
- }
|
82
|
|
- if (empty($Accounts)) {
|
83
|
|
- return 0.0;
|
84
|
|
- }
|
85
|
|
- foreach ($Accounts as $Account) {
|
86
|
|
- if ($Account->account == '') {
|
87
|
|
- return $Account->amount;
|
88
|
|
- }
|
|
77
|
+ /**
|
|
78
|
+ * Ask bitcoind for the total amount of bitcoins received
|
|
79
|
+ *
|
|
80
|
+ * @return float amount
|
|
81
|
+ */
|
|
82
|
+ public static function get_total_received()
|
|
83
|
+ {
|
|
84
|
+ if (defined('BITCOIN_RPC_URL')) {
|
|
85
|
+ $Accounts = BitcoinRpc::listreceivedbyaccount();
|
|
86
|
+ }
|
|
87
|
+ if (empty($Accounts)) {
|
|
88
|
+ return 0.0;
|
|
89
|
+ }
|
|
90
|
+ foreach ($Accounts as $Account) {
|
|
91
|
+ if ($Account->account == '') {
|
|
92
|
+ return $Account->amount;
|
|
93
|
+ }
|
|
94
|
+ }
|
|
95
|
+ return 0.0;
|
89
|
96
|
}
|
90
|
|
- return 0.0;
|
91
|
|
- }
|
92
|
97
|
|
93
|
|
- /**
|
94
|
|
- * Translate bitcoin addresses to user IDs
|
95
|
|
- *
|
96
|
|
- * @param array $Addresses list of bitcoin addresses
|
97
|
|
- * @return array (BitcoinAddress => UserID, ...)
|
98
|
|
- */
|
99
|
|
- public static function get_userids($Addresses) {
|
100
|
|
- if (!is_array($Addresses) || empty($Addresses)) {
|
101
|
|
- return false;
|
102
|
|
- }
|
103
|
|
- $QueryID = G::$DB->get_query_id();
|
104
|
|
- G::$DB->query("
|
|
98
|
+ /**
|
|
99
|
+ * Translate bitcoin addresses to user IDs
|
|
100
|
+ *
|
|
101
|
+ * @param array $Addresses list of bitcoin addresses
|
|
102
|
+ * @return array (BitcoinAddress => UserID, ...)
|
|
103
|
+ */
|
|
104
|
+ public static function get_userids($Addresses)
|
|
105
|
+ {
|
|
106
|
+ if (!is_array($Addresses) || empty($Addresses)) {
|
|
107
|
+ return false;
|
|
108
|
+ }
|
|
109
|
+ $QueryID = G::$DB->get_query_id();
|
|
110
|
+ G::$DB->query("
|
105
|
111
|
SELECT BitcoinAddress, UserID
|
106
|
112
|
FROM users_info
|
107
|
113
|
WHERE BitcoinAddress IN ('" . implode("', '", $Addresses) . "')");
|
108
|
|
- if (G::$DB->has_results()) {
|
109
|
|
- $UserIDs = G::$DB->to_pair(0, 1);
|
110
|
|
- } else {
|
111
|
|
- $UserIDs = [];
|
|
114
|
+ if (G::$DB->has_results()) {
|
|
115
|
+ $UserIDs = G::$DB->to_pair(0, 1);
|
|
116
|
+ } else {
|
|
117
|
+ $UserIDs = [];
|
|
118
|
+ }
|
|
119
|
+ G::$DB->set_query_id($QueryID);
|
|
120
|
+ return $UserIDs;
|
112
|
121
|
}
|
113
|
|
- G::$DB->set_query_id($QueryID);
|
114
|
|
- return $UserIDs;
|
115
|
|
- }
|
116
|
122
|
|
117
|
|
- /**
|
118
|
|
- * Find and process new donations since the last time this function was called.
|
119
|
|
- */
|
120
|
|
- public static function find_new_donations() {
|
121
|
|
- global $Debug;
|
122
|
|
- if (($OldAmount = G::$Cache->get_value('btc_total_received')) === false) {
|
123
|
|
- $QueryID = G::$DB->get_query_id();
|
124
|
|
- G::$DB->query("
|
|
123
|
+ /**
|
|
124
|
+ * Find and process new donations since the last time this function was called.
|
|
125
|
+ */
|
|
126
|
+ public static function find_new_donations()
|
|
127
|
+ {
|
|
128
|
+ global $Debug;
|
|
129
|
+ if (($OldAmount = G::$Cache->get_value('btc_total_received')) === false) {
|
|
130
|
+ $QueryID = G::$DB->get_query_id();
|
|
131
|
+ G::$DB->query("
|
125
|
132
|
SELECT IFNULL(SUM(Amount), 0)
|
126
|
133
|
FROM donations_bitcoin");
|
127
|
|
- list($OldAmount) = G::$DB->next_record(MYSQLI_NUM, false);
|
128
|
|
- G::$DB->set_query_id($QueryID);
|
129
|
|
- }
|
130
|
|
- $NewAmount = self::get_total_received();
|
131
|
|
- if ($NewAmount < $OldAmount) {
|
132
|
|
- // This shouldn't happen. Perhaps bitcoind was restarted recently
|
133
|
|
- // or the block index was removed. Either way, try again later
|
134
|
|
- send_irc('PRIVMSG ' . LAB_CHAN . " :Bad bitcoin donation data (is $NewAmount, was $OldAmount). If this persists, something is probably wrong");
|
135
|
|
- return false;
|
136
|
|
- }
|
137
|
|
- if ($NewAmount > $OldAmount) {
|
138
|
|
- // I really wish we didn't have to do it like this
|
139
|
|
- $QueryID = G::$DB->get_query_id();
|
140
|
|
- G::$DB->query("
|
|
134
|
+ list($OldAmount) = G::$DB->next_record(MYSQLI_NUM, false);
|
|
135
|
+ G::$DB->set_query_id($QueryID);
|
|
136
|
+ }
|
|
137
|
+ $NewAmount = self::get_total_received();
|
|
138
|
+ if ($NewAmount < $OldAmount) {
|
|
139
|
+ // This shouldn't happen. Perhaps bitcoind was restarted recently
|
|
140
|
+ // or the block index was removed. Either way, try again later
|
|
141
|
+ send_irc('PRIVMSG ' . LAB_CHAN . " :Bad bitcoin donation data (is $NewAmount, was $OldAmount). If this persists, something is probably wrong");
|
|
142
|
+ return false;
|
|
143
|
+ }
|
|
144
|
+ if ($NewAmount > $OldAmount) {
|
|
145
|
+ // I really wish we didn't have to do it like this
|
|
146
|
+ $QueryID = G::$DB->get_query_id();
|
|
147
|
+ G::$DB->query("
|
141
|
148
|
SELECT BitcoinAddress, SUM(Amount)
|
142
|
149
|
FROM donations_bitcoin
|
143
|
150
|
GROUP BY BitcoinAddress");
|
144
|
|
- $OldDonations = G::$DB->to_pair(0, 1, false);
|
145
|
|
- G::$DB->set_query_id($QueryID);
|
146
|
|
- $NewDonations = self::get_received();
|
147
|
|
- foreach ($NewDonations as $Address => &$Amount) {
|
148
|
|
- if (isset($OldDonations[$Address])) {
|
149
|
|
- if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
|
150
|
|
- unset($NewDonations[$Address]);
|
151
|
|
- continue;
|
152
|
|
- }
|
153
|
|
- $Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
|
154
|
|
- // PHP doesn't do fixed-point math, and json_decode has already botched the precision
|
155
|
|
- // so let's just round this off to satoshis and pray that we're on a 64 bit system
|
156
|
|
- $Amount = round($Amount - $OldDonations[$Address], 8);
|
|
151
|
+ $OldDonations = G::$DB->to_pair(0, 1, false);
|
|
152
|
+ G::$DB->set_query_id($QueryID);
|
|
153
|
+ $NewDonations = self::get_received();
|
|
154
|
+ foreach ($NewDonations as $Address => &$Amount) {
|
|
155
|
+ if (isset($OldDonations[$Address])) {
|
|
156
|
+ if ($Amount == $OldDonations[$Address]) { // Direct comparison should be fine as everything comes from bitcoind
|
|
157
|
+ unset($NewDonations[$Address]);
|
|
158
|
+ continue;
|
|
159
|
+ }
|
|
160
|
+ $Debug->log_var(array('old' => $OldDonations[$Address], 'new' => $Amount), "New donations from $Address");
|
|
161
|
+ // PHP doesn't do fixed-point math, and json_decode has already botched the precision
|
|
162
|
+ // so let's just round this off to satoshis and pray that we're on a 64 bit system
|
|
163
|
+ $Amount = round($Amount - $OldDonations[$Address], 8);
|
|
164
|
+ }
|
|
165
|
+ $NewDonations[$Address] = $Amount;
|
|
166
|
+ }
|
|
167
|
+ $Debug->log_var($NewDonations, '$NewDonations');
|
|
168
|
+ foreach (self::get_userids(array_keys($NewDonations)) as $Address => $UserID) {
|
|
169
|
+ Donations::regular_donate($UserID, $NewDonations[$Address], 'Bitcoin Parser', '', 'BTC');
|
|
170
|
+ self::store_donation($Address, $NewDonations[$Address]);
|
|
171
|
+ }
|
|
172
|
+ G::$Cache->cache_value('btc_total_received', $NewAmount, 0);
|
157
|
173
|
}
|
158
|
|
- $NewDonations[$Address] = $Amount;
|
159
|
|
- }
|
160
|
|
- $Debug->log_var($NewDonations, '$NewDonations');
|
161
|
|
- foreach (self::get_userids(array_keys($NewDonations)) as $Address => $UserID) {
|
162
|
|
- Donations::regular_donate($UserID, $NewDonations[$Address], 'Bitcoin Parser', '', 'BTC');
|
163
|
|
- self::store_donation($Address, $NewDonations[$Address]);
|
164
|
|
- }
|
165
|
|
- G::$Cache->cache_value('btc_total_received', $NewAmount, 0);
|
166
|
174
|
}
|
167
|
|
- }
|
168
|
175
|
|
169
|
|
- /**
|
170
|
|
- * Record a donation in the database
|
171
|
|
- *
|
172
|
|
- * @param string $Address bitcoin address
|
173
|
|
- * @param double $Amount amount of bitcoins transferred
|
174
|
|
- */
|
175
|
|
- public static function store_donation($Address, $Amount) {
|
176
|
|
- if (!is_numeric($Amount) || $Amount <= 0) {
|
177
|
|
- // Panic!
|
178
|
|
- return false;
|
179
|
|
- }
|
180
|
|
- G::$DB->query("
|
|
176
|
+ /**
|
|
177
|
+ * Record a donation in the database
|
|
178
|
+ *
|
|
179
|
+ * @param string $Address bitcoin address
|
|
180
|
+ * @param double $Amount amount of bitcoins transferred
|
|
181
|
+ */
|
|
182
|
+ public static function store_donation($Address, $Amount)
|
|
183
|
+ {
|
|
184
|
+ if (!is_numeric($Amount) || $Amount <= 0) {
|
|
185
|
+ // Panic!
|
|
186
|
+ return false;
|
|
187
|
+ }
|
|
188
|
+ G::$DB->query("
|
181
|
189
|
INSERT INTO donations_bitcoin
|
182
|
190
|
(BitcoinAddress, Amount)
|
183
|
191
|
VALUES
|
184
|
192
|
('$Address', $Amount)");
|
185
|
|
- }
|
186
|
|
-}
|
|
193
|
+ }
|
|
194
|
+}
|