From 60ed9d64bcfef666056ea5033f93f897baafee34 Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 11 Mar 2015 14:32:28 +0800 Subject: [PATCH] generate bitcoin address using chain.com API --- scripts/generate.php | 195 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 scripts/generate.php diff --git a/scripts/generate.php b/scripts/generate.php new file mode 100644 index 00000000..c51fc69f --- /dev/null +++ b/scripts/generate.php @@ -0,0 +1,195 @@ + + * @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 . + */ +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"; +}