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 .= '