kevin
9 years ago
1 changed files with 195 additions and 0 deletions
Split View
Diff Options
@ -0,0 +1,195 @@ |
|||
<?php |
|||
/** |
|||
* generate.php |
|||
* |
|||
* generate bitcoin address list file for ss-server/shadowsocks-libev. |
|||
* |
|||
* @author Pan Zhibiao <panzhibiao@tangpool.com> |
|||
* @since 2014-03 |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU General Public License as published by |
|||
* the Free Software Foundation, either version 3 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
*/ |
|||
date_default_timezone_set("Etc/GMT+0"); |
|||
|
|||
/* |
|||
* config settings |
|||
*/ |
|||
$_CFG = array(); |
|||
// API Key for Chain.com
|
|||
$_CFG['API-KEY-ID'] = "DEMO-4a5e1e4"; |
|||
// server bitcoin address which receive btc transactions from customers
|
|||
$_CFG['server_baddress'] = "1LDjqcu3rSUkWjL219oZTsHg79S9K6vPwP"; |
|||
$_CFG['cache_file'] = "/var/ss/{$_CFG['server_baddress']}-cached_txs.txt"; |
|||
$_CFG['ss_server_file'] = "/var/ss/{$_CFG['server_baddress']}-list-ss-server.txt"; |
|||
// price for one day, unit: satoshi
|
|||
$_CFG['satoshi_per_day'] = 15000; |
|||
|
|||
// load exist parsed txs
|
|||
$exist_txs = get_exist_txs(); |
|||
// try load new txs
|
|||
$exist_txs = try_load_txs($exist_txs); |
|||
// write cache
|
|||
put_exist_txs($exist_txs); |
|||
// dump file for ss-server
|
|||
dump_for_ss_server($exist_txs); |
|||
|
|||
exit; |
|||
|
|||
|
|||
|
|||
function dump_for_ss_server($exist_txs) { |
|||
global $_CFG; |
|||
|
|||
$address = array(); |
|||
$now = time(); |
|||
foreach ($exist_txs as $_tx) { |
|||
// total days
|
|||
$days = bcdiv($_tx['value'], $_CFG['satoshi_per_day'], 2); |
|||
|
|||
// passed days
|
|||
assert($now > $_tx['timestamp']); |
|||
$passed_days = bcdiv($now - $_tx['timestamp'], 86400, 2); |
|||
|
|||
if ($days <= $passed_days) { |
|||
continue; // expired
|
|||
} |
|||
$address[] = $_tx['address']; |
|||
} |
|||
$str = implode("\n", $address)."\n"; |
|||
|
|||
LOGI("dump ".count($address)." address to ss_server_file"); |
|||
if (file_put_contents($_CFG['ss_server_file'], $str) == false) { |
|||
LOGI("write file fail: {$_CFG['ss_server_file']}"); |
|||
} |
|||
} |
|||
|
|||
|
|||
function try_load_txs($exist_txs) { |
|||
global $_CFG; |
|||
|
|||
$next_range = ""; |
|||
$run_flag = 1; |
|||
while ($run_flag) { |
|||
$res = get_address_list(100/*limit*/, $next_range); |
|||
// var_dump($res);
|
|||
usleep(500000); // 500ms
|
|||
|
|||
if (empty($res['body'])) { |
|||
break; // no more records
|
|||
} |
|||
if (!empty($res['next_range'])) { |
|||
$next_range = $res['next_range']; |
|||
} else { |
|||
$run_flag = 0; // next page is empty
|
|||
} |
|||
|
|||
$new_cnt = 0; |
|||
foreach ($res['body'] as $_tx) { |
|||
if (!empty($exist_txs[$_tx['hash']])) { |
|||
continue; // already exist
|
|||
} |
|||
if (empty($_tx['inputs'][0]['addresses'][0])) { |
|||
continue; // can't get first input address
|
|||
} |
|||
// use first input address as payment address
|
|||
$input_addr = $_tx['inputs'][0]['addresses'][0]; |
|||
|
|||
// check server address
|
|||
foreach ($_tx['outputs'] as $_output) { |
|||
if (empty($_output['addresses'][0]) || |
|||
$_output['addresses'][0] != $_CFG['server_baddress']) { |
|||
continue; |
|||
} |
|||
$exist_txs[$_tx['hash']] = array( |
|||
'address' => $input_addr, |
|||
'value' => $_output['value'], |
|||
'timestamp' => strtotime($_tx['chain_received_at']), |
|||
); |
|||
$new_cnt++; |
|||
LOGI("find new tx: {$_tx['hash']}, value: {$_output['value']}, address: {$input_addr}, received: {$_tx['chain_received_at']}"); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if ($new_cnt == 0 && count($res['body']) > 0) { |
|||
break; // stop, mean all records are exists
|
|||
} |
|||
} |
|||
return $exist_txs; |
|||
} |
|||
|
|||
function get_exist_txs() { |
|||
global $_CFG; |
|||
if (is_readable($_CFG['cache_file'])) { |
|||
return json_decode(file_get_contents($_CFG['cache_file']), 1); |
|||
} |
|||
return array(); |
|||
} |
|||
|
|||
function put_exist_txs($exist_txs) { |
|||
global $_CFG; |
|||
if (!file_put_contents($_CFG['cache_file'], json_encode($exist_txs))) { |
|||
LOGI("file put contents fail, file: {$_CFG['cache_file']}"); |
|||
} |
|||
} |
|||
|
|||
function get_address_list($limit, $range) { |
|||
global $_CFG; |
|||
|
|||
$res = array(); |
|||
$custom_headers = array(); |
|||
|
|||
$url = "https://api.chain.com/v2/bitcoin/addresses/"; |
|||
$url .= rawurlencode($_CFG['server_baddress'])."/transactions?api-key-id="; |
|||
$url .= rawurlencode($_CFG['API-KEY-ID']); |
|||
$url .= "&limit=".intval($limit); |
|||
if ($range != "") { |
|||
$custom_headers[] = "Range: ".$range; |
|||
} |
|||
|
|||
$ch = curl_init(); |
|||
curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE); |
|||
curl_setopt($ch, CURLOPT_HEADER, 1); |
|||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
|||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); |
|||
curl_setopt($ch, CURLOPT_URL, $url); |
|||
curl_setopt($ch, CURLOPT_TIMEOUT, 30); |
|||
if (!empty($custom_headers)) { |
|||
curl_setopt($ch, CURLOPT_HTTPHEADER, $custom_headers); |
|||
} |
|||
|
|||
$r = curl_exec($ch); |
|||
$curl_errno = curl_errno($ch); |
|||
$curl_error = curl_error($ch); |
|||
curl_close($ch); |
|||
|
|||
if ($curl_errno > 0) { |
|||
LOGI("curl request fail, errno: {$curl_errno}, error: {$curl_error}"); |
|||
return false; |
|||
} |
|||
|
|||
list($header, $body) = explode("\r\n\r\n", $r, 2); |
|||
// find next range
|
|||
preg_match("/Next-Range: ([^\r]*)/", $header, $matches); |
|||
if (!empty($matches[1])) { |
|||
$res['next_range'] = $matches[1]; |
|||
} |
|||
$res['body'] = json_decode($body, 1); |
|||
return $res; |
|||
} |
|||
|
|||
|
|||
function LOGI($msg) { |
|||
echo date("Y-m-d H:i:s"), " $msg\n"; |
|||
} |
Write
Preview
Loading…
Cancel
Save