diff --git a/.htaccess b/.htaccess index cbbdbf5..7f611ea 100644 --- a/.htaccess +++ b/.htaccess @@ -3,7 +3,9 @@ RewriteEngine on RewriteBase / + RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] + diff --git a/README.md b/README.md index e58ac50..53b1c3c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,16 @@ THIS IS AN OPEN-SOURCE TOOL WITH NO RESPONSIBILITY FOR ACTIONS TAKEN BY THIRD PA --- -###### A Hashpower Voting System for Bitcoin Global Adoption. +##### BMP is a Hashpower Voting System for Bitcoin Global Adoption +- [x] Hardware-wallet auth. +- [x] Multi-blockchain SHA-256 merge. +- [x] Real-time hashpower chat. +- [x] Nick change. +- [x] Voting, with multiple points and options. +- [x] Votes with hashpower. +- [x] Rectifiable votes (in open votings). +- [x] 100% verifiable, on-chain, open-source. + ## Why @@ -64,65 +73,57 @@ Extract from [ABC vs BSV Hash War (Part III)](https://medium.com/@jiangzhuoer/ab ## How -Talking and voting with hashpower -to discover consensus- in the most secure voting system known. +Talking and voting with hashpower -to discover consensus- in the most secure voting system ever known. ## What -#### [bmp.virtualpol.com](https://bmp.virtualpol.com) +#### [bmp.virtualpol.com](https://bmp.virtualpol.com) [version 0.2-beta]
-[BMP](https://bmp.virtualpol.com) is a [LAMP](https://en.wikipedia.org/wiki/LAMP_(software_bundle)) web system, completely on-chain, verifiable, replicable and driven by hashpower. - -BMP works connected to a Bitcoin Cash client by RPC to read blocks and transactions. -Blockchain data is transformed [with this PHP](https://github.com/JavierGonzalez/BMP/blob/master/autoload/bmp.php) in 3 SQL tables: **[Blocks](https://bmp.virtualpol.com/info/blocks)**, **[Miners](https://bmp.virtualpol.com/info/miners)** and **[Actions](https://bmp.virtualpol.com/info/actions)**. +[BMP](https://bmp.virtualpol.com) is a voting system, completely on-chain, verifiable, replicable and driven by hashpower. A robust and expandable base system. Merge all Bitcoin SHA-256 hashpower. Expanding the vision of Satoshi Nakamoto [whitepaper](https://www.bitcoin.com/bitcoin.pdf). +BMP is a [LAMP](https://en.wikipedia.org/wiki/LAMP_(software_bundle)) web system connected to a multiple Bitcoin client -via RPC- to read blocks and transactions. Blockchain data is processed [with this PHP](https://github.com/JavierGonzalez/BMP/blob/master/autoload/bmp.php) in three SQL tables: **[Blocks](https://bmp.virtualpol.com/info/blocks)**, **[Miners](https://bmp.virtualpol.com/info/miners)** and **[Actions](https://bmp.virtualpol.com/info/actions)**. -Actions without hashpower are ignored. Miners power changes with each block. Actions power never changes. - -Actions are composed in JavaScript and broadcast with [Trezor Connect](https://github.com/trezor/connect/blob/develop/docs/methods/composeTransaction.md) (more hardware wallets in future). -BMP does not store private keys. The entire BMP database is public information. +Actions are stored in Bitcoin Cash (BCH) because is fast, cheap and stable. -More in **[BMP Protocol](https://bmp.virtualpol.com/protocol)** and paper in [Chinese](https://virtualpol.com/BMP_CN.pdf), [English](https://virtualpol.com/BMP_EN.pdf) and [Spanish](https://virtualpol.com/BMP_ES.pdf). +Actions without hashpower are ignored. Miners power (%) changes with each block. Actions power never changes. +Actions are composed in JavaScript and broadcast with [Trezor Connect](https://github.com/trezor/connect/blob/develop/docs/methods/composeTransaction.md) (more hardware wallets in future). -#### Features +BMP does not store private keys and the database is public information. -* Hardware-wallet authentication. -* Real-time chat with hashpower. -* Nick change. -* Voting with multiple config, points and options. -* Votes with hashpower. -* Rectifiable votes (in open voting). -* 100% verifiable on-chain. +More in **[BMP Protocol](https://bmp.virtualpol.com/protocol)** and the BMP paper in [English](https://virtualpol.com/BMP_EN.pdf), [Chinese](https://virtualpol.com/BMP_CN.pdf) and [Spanish](https://virtualpol.com/BMP_ES.pdf). #### Requirements to participate -1. Your address in a coinbase output in the last `2,016` blocks of BCH. +1. Your address in a coinbase output in the last `2,016` blocks of BTC, BCH or BSV. 2. Trezor hardware wallet. #### Hashpower signaling 1. **power_by_value** -By default, BMP calculates the hashpower percentage of each output address with the coinbase `value`. This makes it compatible with all blocks and with P2Pool even the smallest miner can participate right now. +By default, BMP calculates the hashpower percentage of each output address with the coinbase `value`. This makes it compatible with all blocks. With P2Pool, even the smallest miner can participate, right now. 2. **power_by_opreturn** In order not to interfere with mining operations, there is a second method that allows to signal hashpower quotas in one or more addresses in coinbase OP_RETURN output. This ignores the value and allows the delegation of hashpower with simplicity. -In this way, miners can easily delegate hashpower to anyone else. - +In this way, with simplicity, miners can delegate hashpower in other people to participate. #### Requirements to deploy -1. Bitcoin ABC client, with `-txindex` -2. GNU/Linux -3. Apache -4. MariaDB database -5. PHP +1. GNU/Linux +2. Apache +3. MariaDB SQL database +4. PHP +5. Bitcoin BCH client, with `-txindex` (main for actions) +6. Bitcoin BTC client +7. Bitcoin BSV client + #### Tested environment @@ -144,7 +145,7 @@ In this way, miners can easily delegate hashpower to anyone else. 2. Configure RPC and SQL access by renaming `autoload/_password.php`. 3. Execute `scheme.sql` in a new SQL database. 4. Set a `crontab` every minute with: `curl https://bmp.domain.com/update`. -5. Wait synchronization. +5. Wait synchronizations. #### Known problems diff --git a/__maximum_simplicity/config.php b/__maximum_simplicity/config.php index 359cb3e..e857f4b 100644 --- a/__maximum_simplicity/config.php +++ b/__maximum_simplicity/config.php @@ -1,6 +1,8 @@ '."\n"; + echo ++$__['___'].'.   '.date('Y-m-d H:i:s').'   '.implode('   ', __profiler()).'   '; - ob_end_flush(); - echo ''; - } - - echo '
'.++$_['crono_count'].'.   '.date('Y-m-d H:i:s').'   '; - echo number_format(($now-$_['crono'])/1000000, 2).' ms   '; - - if (is_array($echo) OR is_object($echo)) + if (is_string($echo)) + echo $echo; + else if (is_array($echo) OR is_object($echo)) print_r2($echo); - else if ($echo!=='') + else var_dump($echo); + if ($scroll_down) { - echo ''; + + if ($__['___']==1) { + + if (function_exists('apache_setenv')) + @apache_setenv('no-gzip', 1); + + ob_end_flush(); + echo ''; + } + + echo ''; flush(); ob_flush(); } - $_['crono'] = hrtime(true); + $__['crono'] = hrtime(true); } @@ -75,12 +100,6 @@ function every($seconds=60, $id=0) { -function ram() { - return number_format(memory_get_usage(true)/1024).' kb'; -} - - - function redirect($url='/') { header('Location: '.$url); exit; @@ -95,5 +114,5 @@ function shell($command) { function num($number, $decimals=0) { - return number_format($number, $decimals, '.', ','); + return number_format((float)$number, $decimals, '.', ','); } diff --git a/__maximum_simplicity/router.php b/__maximum_simplicity/router.php index b639806..e42a095 100644 --- a/__maximum_simplicity/router.php +++ b/__maximum_simplicity/router.php @@ -34,7 +34,6 @@ foreach ($public AS $_module) { if (file_exists($_module)) { - // Sub-autoload if (file_exists(dirname($_module).'/*.php')) include(dirname($_module).'/*.php'); diff --git a/__maximum_simplicity/start.php b/__maximum_simplicity/start.php index 7600e66..c03438b 100644 --- a/__maximum_simplicity/start.php +++ b/__maximum_simplicity/start.php @@ -1,31 +1,25 @@ = ".e($height))) - exit; + if (sql("SELECT id FROM blocks WHERE blockchain = '".$blockchain."' AND height = ".e($height))) + return false; $block = rpc_get_block($height, $blockchain); @@ -34,7 +34,7 @@ function block_insert($height, $blockchain=BLOCKCHAIN_ACTIONS) { 'nonce' => $block['nonce'], 'difficulty' => $block['difficulty'], 'coinbase' => $coinbase['vin'][0]['coinbase'], - 'pool' => pool_decode(hex2bin($coinbase['vin'][0]['coinbase']))['name'], + 'pool' => pool_decode(hex2bin($coinbase['vin'][0]['coinbase']), $coinbase_hashpower)['name'], 'power_by' => $coinbase_hashpower['power_by'], 'quota_total' => $coinbase_hashpower['quota_total'], 'hashpower' => $block_hashpower, @@ -59,7 +59,7 @@ function block_insert($height, $blockchain=BLOCKCHAIN_ACTIONS) { update_power(); - if ($blockchain !== BLOCKCHAIN_ACTIONS) + if ($blockchain != BLOCKCHAIN_ACTIONS) return true; @@ -91,10 +91,10 @@ function coinbase_hashpower($coinbase) { // There are power signalled in coinbase OP_RETURN? foreach ($coinbase['vout'] AS $tx_vout) - if ($rd = op_return_decode($tx_vout['scriptPubKey']['hex'])) + if ($miner_by_opreturn = op_return_decode($tx_vout['scriptPubKey']['hex'])) $output['miners'][] = array( - 'quota' => $rd['p1'], - 'address' => address_normalice($rd['p2']), + 'quota' => $miner_by_opreturn['p1'], + 'address' => address_normalice($miner_by_opreturn['p2']), ); @@ -216,9 +216,9 @@ function get_action_tx($tx, $blockchain=BLOCKCHAIN_ACTIONS) { } - +// 6a1000036e69636b20202020202054657374 function op_return_decode($op_return) { - + if (!ctype_xdigit($op_return)) return false; @@ -246,7 +246,8 @@ function op_return_decode($op_return) { $counter = $metadata_start_bytes + 1; foreach (BMP_PROTOCOL['actions'][$action_id] AS $p => $v) { - if ($p AND $parameter = substr($op_return, $counter*2, $v['size']*2)) { + if (is_numeric($p) AND $parameter = substr($op_return, $counter*2, $v['size']*2)) { + $counter += $v['size']; if ($v['decode']=='hex2bin') @@ -260,9 +261,8 @@ function op_return_decode($op_return) { $parameter = trim($parameter); - if (is_array($v['options'])) - if (!array_key_exists($parameter, $v['options'])) - return false; + if (is_array($v['options']) AND !array_key_exists($parameter, $v['options'])) + return false; if ($v['min'] AND $parameter < $v['min']) return false; @@ -280,10 +280,10 @@ function op_return_decode($op_return) { function get_mempool($blockchain=BLOCKCHAIN_ACTIONS) { - global $mempool_cache; + global $__mempool_cache; foreach (rpc_get_mempool($blockchain) AS $txid) - if (!$mempool_cache[$txid] AND $mempool_cache[$txid] = true) + if (!$__mempool_cache[$txid] AND $__mempool_cache[$txid] = true) if (!sql("SELECT id FROM actions WHERE txid = '".$txid."' LIMIT 1")) if ($action = get_action($txid, $blockchain)) $actions[] = $action; diff --git a/autoload/bmp_actions.php b/autoload/bmp_actions.php index fa5266a..1f38e66 100644 --- a/autoload/bmp_actions.php +++ b/autoload/bmp_actions.php @@ -8,6 +8,11 @@ function update_actions() { foreach (sql("SELECT address, p2 AS nick FROM actions WHERE action = 'miner_parameter' AND p1 = 'nick' ORDER BY time ASC") AS $r) sql_update('miners', array('nick' => $r['nick']), "address = '".$r['address']."'"); + // Menu caches + sql_key_value('cache_blocks_num', round(sql("SELECT SUM(hashpower) AS ECHO FROM blocks")/BLOCK_WINDOW)); + sql_key_value('cache_miners_num', sql("SELECT COUNT(DISTINCT address) AS ECHO FROM miners")); + sql_key_value('cache_actions_num', sql("SELECT COUNT(*) AS ECHO FROM actions")); + } @@ -19,9 +24,9 @@ function action_voting_info($txid) { // Refact $voting['height_finish'] = $voting['height'] + $voting['blocks_to_finish']; - $last_height = sql("SELECT height FROM blocks ORDER BY height DESC LIMIT 1")[0]['height']; + $last_height = sql("SELECT height FROM blocks WHERE blockchain = '".BLOCKCHAIN_ACTIONS."' ORDER BY height DESC LIMIT 1")[0]['height']; - $voting['status'] = ($voting['height_finish']>=$last_height?'open':'close'); + $voting['status'] = ($voting['height_finish']>=$last_height || !$voting['height']?'open':'close'); if ($voting['status']=='open') $voting['close_in'] = $voting['height_finish']-$last_height; @@ -74,7 +79,7 @@ function action_voting_info($txid) { // Refact return false; - $blocks_num = sql("SELECT COUNT(*) AS ECHO FROM blocks"); + $blocks_num = sql("SELECT COUNT(*) AS ECHO FROM blocks WHERE blockchain = '".BLOCKCHAIN_ACTIONS."'"); $result = sql("SELECT txid, address, p2 AS type_vote, p3 AS voting_validity, p4 AS vote, (SELECT SUM(power) FROM miners WHERE address = actions.address) AS power, @@ -99,7 +104,7 @@ function action_voting_info($txid) { // Refact $voting['validity'][($vote['voting_validity']==='1'?'valid':'not_valid')] += $vote['power']; $voting['options'][$vote['vote']]['votes']++; - $voting['options'][$vote['vote']]['power'] += $vote['power']; + $voting['options'][$vote['vote']]['power'] += round($vote['power'], POWER_PRECISION); $voting['options'][$vote['vote']]['hashpower'] += $vote['hashpower']/$blocks_num; } diff --git a/autoload/bmp_protocol.php b/autoload/bmp_protocol.php index 61b3e1e..0b58548 100644 --- a/autoload/bmp_protocol.php +++ b/autoload/bmp_protocol.php @@ -40,7 +40,7 @@ 'action' => 'miner_parameter', 'status' => 'implemented', 'description' => '', - 1 => array('size' => 10, 'name'=>'key', 'decode'=>'hex2bin', 'options'=>array('nick', 'email')), + 1 => array('size' => 10, 'name'=>'key', 'decode'=>'hex2bin', 'options'=>array('nick'=>'nick', 'email'=>'email')), 2 => array('size' => 200, 'name'=>'value', 'decode'=>'hex2bin'), ), @@ -80,18 +80,15 @@ ), - - '07' => array( 'action' => 'bmp_parameter', - 'status' => 'planned', + 'status' => 'idea', 1 => array('size' => 10, 'name'=>'key', 'decode'=>'hex2bin'), 2 => array('size' => 200, 'name'=>'value', 'decode'=>'hex2bin'), ), - '08' => array( 'action' => 'cancel', 'status' => 'idea', diff --git a/autoload/bmp_utils.php b/autoload/bmp_utils.php index db8e256..46ae79f 100644 --- a/autoload/bmp_utils.php +++ b/autoload/bmp_utils.php @@ -3,11 +3,17 @@ function get_new_blocks() { + $output = false; + foreach (BLOCKCHAINS AS $blockchain) - get_new_block($blockchain); + if (get_new_block($blockchain)) + $output = true; + + return $output; } + function get_new_block($blockchain=BLOCKCHAIN_ACTIONS) { $rpc_height = rpc_get_best_height($blockchain); @@ -19,12 +25,14 @@ function get_new_block($blockchain=BLOCKCHAIN_ACTIONS) { if ($bmp_height) $height = $bmp_height + 1; - else + else if ($blockchain==BLOCKCHAIN_ACTIONS) $height = BMP_GENESIS_BLOCK; + else + $height = rpc_get_best_height($blockchain)-BLOCK_WINDOW; - sql_lock(['blocks', 'miners', 'actions']); - block_insert($height); - sql_unlock(); + + block_insert($height, $blockchain); + return true; } @@ -46,49 +54,62 @@ function revert_bytes($hex) { } -function pool_decode($coinbase) { - global $pools_json_cache; +function pool_decode($coinbase, $coinbase_hashpower=false) { + global $__pools_json_cache; - if (!$pools_json_cache) - $pools_json_cache = json_decode(file_get_contents('lib/pools.json'), true); + if (!$__pools_json_cache) + $__pools_json_cache = json_decode(file_get_contents('lib/pools.json'), true); - foreach ($pools_json_cache['coinbase_tags'] AS $tag => $pool) + foreach ($__pools_json_cache['coinbase_tags'] AS $tag => $pool) if (strpos($coinbase, $tag)!==false) return $pool; + if (count($coinbase_hashpower['miners'])>=20) // Hack + return array('name' => 'P2Pool'); + return null; } function address_normalice($address) { - include_once('lib/cashaddress.php'); - - if (substr($address,0,12)=='bitcoincash:') + if (substr($address,0,12)=='bitcoincash:') { + include_once('lib/cashaddress.php'); $address = \CashAddress\CashAddress::new2old($address, false); + } return trim($address); } -function hashpower_humans($hps, $decimals=0) { +function hashpower_humans($hps, $unit=false, $decimals=0) { if (!is_numeric($hps) OR $hps==0) return ''; - $prefix = array( - 1000000000000000000000 => 'Z', - 1000000000000000000 => 'E', - 1000000000000000 => 'P', - 1000000000000 => 'T', - 1000000000 => 'G', + $units = array( + 'E' => 1000000000000000000, + 'P' => 1000000000000000, + 'T' => 1000000000000, ); + + if ($units[$unit]) + return num($hps/$units[$unit], $decimals).' '.$unit.'H/s'; + + foreach ($units AS $u => $x) + if ($hps/$x>=100 OR $u=='T') + return num($hps/$x, $decimals).' '.$u.'H/s'; + +} - foreach ($prefix AS $x => $p) - if ($hps/$x >= 10 OR $p=='G') - return num($hps/$x, $decimals).' '.$p.'H/s'; +function hashpower_humans_phs($hps, $decimals=0) { + + if (!is_numeric($hps) OR $hps==0) + return ''; + + return num($hps/1000000000000000, $decimals).' PH/s'; } diff --git a/autoload/html.php b/autoload/html.php index 71695d3..f9ed20b 100644 --- a/autoload/html.php +++ b/autoload/html.php @@ -2,11 +2,15 @@ function html_table($data, $config=false) { - + if (!is_array($data)) return ''; - + + // Header + if ($config['tr_th_extra']) + $html .= $config['tr_th_extra']; + $html .= ''; foreach ((array)$data[key($data)] AS $key => $value) { @@ -15,7 +19,7 @@ function html_table($data, $config=false) { $html .= ''.ucfirst($key).''; } - $html .= ''; + $html .= ''."\n"; // Rows @@ -33,6 +37,9 @@ function html_table($data, $config=false) { if ($config[$key]['monospace']) $td_extra .= ' class="monospace"'; + if ($config[$key]['background_color']) + $td_extra .= ' style="background-color:'.$config[$key]['background_color'].';"'; + if ($config[$key]['function']) $column = call_user_func($config[$key]['function'], $column); @@ -56,11 +63,11 @@ function html_table($data, $config=false) { $html .= ''.$column.''; } - $html .= ''; + $html .= ''."\n"; } - return ''.$html.'
'; + return "\n\n".''.$html.'
'."\n\n"; } diff --git a/autoload/rpc.php b/autoload/rpc.php index fee8f39..13a3752 100644 --- a/autoload/rpc.php +++ b/autoload/rpc.php @@ -1,20 +1,25 @@ error(); + if (!$__rpc[$blockchain]) + echo $__rpc[$blockchain]->error(); } - return $_rpc[$blockchain]; + $__rpc['count']++; + + return $__rpc[$blockchain]; } diff --git a/autoload/sql.php b/autoload/sql.php index 64f26a6..d840401 100644 --- a/autoload/sql.php +++ b/autoload/sql.php @@ -2,7 +2,7 @@ function sql_connect($server_sql=false) { - global $_sql; + global $__sql; if (!$server_sql) $server_sql = URL_SQL; @@ -15,7 +15,7 @@ function sql_connect($server_sql=false) { $sql_link = @mysqli_connect($p['host'], $p['user'], $p['pass'], str_replace('/', '', $p['path']), $p['port']); - $_sql['link'][] = $sql_link; + $__sql['link'][] = $sql_link; if (!$sql_link) { echo 'ERROR: Database connect error.'; @@ -32,19 +32,20 @@ function sql_connect($server_sql=false) { function sql_link() { - global $_sql; + global $__sql; - if (!$_sql['link']) + if (!$__sql['link']) sql_connect(); - return $_sql['link'][0]; + return $__sql['link'][0]; } function sql($query) { - - $result = mysqli_query(sql_link(), $query); + global $__sql; + + $result = mysqli_query(sql_link(), $query); if ($result===true OR $result===false) return $result; @@ -56,6 +57,8 @@ function sql($query) { if (isset($output[0]['ECHO'])) return $output[0]['ECHO']; + $__sql['count']++; + return $output; } @@ -220,12 +223,12 @@ function sql_unlock() { function sql_close() { - global $sql; + global $__sql; - foreach ((array)$sql['link'] AS $link) - @mysqli_close($link); + foreach ((array)$__sql['link'] AS $link) + mysqli_close($link); - unset($sql['link']); + unset($__sql['link']); } diff --git a/public/api.php b/public/api.php index f473020..5a96f08 100644 --- a/public/api.php +++ b/public/api.php @@ -1,7 +1,7 @@ ' + td + ''; + html += '' + td + '\n'; last = value['time']; }); diff --git a/public/chat/index.php b/public/chat/index.php index f7ada46..d03d134 100644 --- a/public/chat/index.php +++ b/public/chat/index.php @@ -1,15 +1,15 @@ _('Blocks'), '/info/miners' => _('Miners'), '/info/actions' => _('Actions'), diff --git a/public/index.php b/public/index.php index d8b4dfc..f2b3912 100644 --- a/public/index.php +++ b/public/index.php @@ -1,22 +1,3 @@ - - -BMP - - - - - - -
- -
- - - -*/ \ No newline at end of file diff --git a/public/info/action.php b/public/info/action.php index c96fa97..4048ceb 100644 --- a/public/info/action.php +++ b/public/info/action.php @@ -1,6 +1,6 @@ $value) { @@ -18,13 +18,6 @@ if ($value['actions']) $data[$key]['actions'] = html_b($value['actions']); - if (!$time_last) - $time_last = date('Y-m-d H:i:s'); - - $duration = strtotime($time_last) - strtotime($value['time']); - $data[$key]['minutes'] = num($duration/60,0); - $time_last = $value['time']; - $data[$key]['tx_count'] = num($value['tx_count']); $data[$key]['hashpower'] = hashpower_humans($value['hashpower']); @@ -38,6 +31,5 @@ 'actions' => array('align' => 'right'), 'hash' => array('monospace' => true), 'tx_count' => array('align' => 'right', 'th' => 'TX'), - 'minutes' => array('align' => 'right'), 'hashpower' => array('align' => 'right'), )); diff --git a/public/info/miner.php b/public/info/miner.php index ff97596..09455ec 100644 --- a/public/info/miner.php +++ b/public/info/miner.php @@ -1,10 +1,10 @@ $_template['title'], + 'title' => $__template['title'], 'version' => BMP_VERSION, 'block_window' => BLOCK_WINDOW, ); diff --git a/public/info/miners.php b/public/info/miners.php index 4ef0736..f0805ab 100644 --- a/public/info/miners.php +++ b/public/info/miners.php @@ -1,8 +1,8 @@ _('Blocks'), '/info/miners' => _('Miners'), '/info/actions' => _('Actions'), @@ -32,7 +32,7 @@ - + diff --git a/public/protocol.php b/public/protocol.php index 5635538..b197fe2 100644 --- a/public/protocol.php +++ b/public/protocol.php @@ -1,13 +1,18 @@ $action) { $td = array( 'status' => $action['status'], 'coinbase' => ($action['coinbase']?html_b('x'):''), + + 'BTC' => ($action['coinbase']?html_b('x'):''), + 'BCH' => ($action['status']=='implemented'?html_b('x'):''), + 'BSV' => ($action['coinbase']?html_b('x'):''), + 'action' => $action['action'], 'BMP' => BMP_PROTOCOL['prefix'], @@ -38,13 +43,16 @@ 'coinbase' => array('align' => 'center'), ); +foreach (BLOCKCHAINS AS $blockchain) + $config[$blockchain] = array('align' => 'center'); + ?>

Protocol

@@ -32,19 +35,19 @@ function menu_active($url) { > Blocks - + > Miners - + > Actions - + @@ -61,19 +64,11 @@ function menu_active($url) { Code

-

- - -
- '.num($blocks_num).' blocks of '.BLOCK_WINDOW.'

'; +
+ ', __profiler($__['crono_start']))?> +
-echo '
'.num((hrtime(true)-$_['crono'])/100000).' ms   '.ram().'
'; + -echo ''; \ No newline at end of file