diff --git a/ethereum.routing.yml b/ethereum.routing.yml index 38b215b..5ed0400 100644 --- a/ethereum.routing.yml +++ b/ethereum.routing.yml @@ -1,7 +1,7 @@ ethereum.status: path: '/admin/reports/ethereum/{server_id}' defaults: - _controller: 'Drupal\ethereum\Controller\EthereumController::status' + _controller: 'Drupal\ethereum\Controller\EthereumStatusPageController::status' _title: 'Ethereum' server_id: NULL requirements: @@ -50,7 +50,7 @@ entity.ethereum_server.delete_form: entity.ethereum_server.enable: path: '/admin/config/ethereum/network/server/{ethereum_server}/enable' defaults: - _controller: '\Drupal\ethereum\Controller\EthereumUIController::ajaxOperation' + _controller: '\Drupal\ethereum\Controller\EthereumController::performOperation' op: enable requirements: _permission: 'administer site configuration' @@ -59,7 +59,7 @@ entity.ethereum_server.enable: entity.ethereum_server.disable: path: '/admin/config/ethereum/network/server/{ethereum_server}/disable' defaults: - _controller: '\Drupal\ethereum\Controller\EthereumUIController::ajaxOperation' + _controller: '\Drupal\ethereum\Controller\EthereumController::performOperation' op: disable requirements: _permission: 'administer site configuration' diff --git a/src/Controller/EthereumController.php b/src/Controller/EthereumController.php index 4269d29..8e4987c 100644 --- a/src/Controller/EthereumController.php +++ b/src/Controller/EthereumController.php @@ -3,13 +3,12 @@ namespace Drupal\ethereum\Controller; use Drupal\Core\Controller\ControllerBase; - use Ethereum\Ethereum; use Drupal\ethereum\EthereumServerInterface; -use Ethereum\DataType\EthBlockParam; -use Ethereum\DataType\EthB; use Drupal\Core\Render\Markup; use Symfony\Component\HttpFoundation\Request; +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\ReplaceCommand; /** * Controller routines for Ethereum routes. @@ -61,243 +60,35 @@ public function debug($clear = FALSE) { } } + /** - * Displays the ethereum status report page. - * - * This page provides an overview of Ethereum functions and usage. - * - * @param string|null $server_id - * The id of the server to report on. + * Calls an operation on an ethereum_server entity and reloads the listing page. * + * @param \Drupal\ethereum\EthereumServerInterface $ethereum_server + * The server being acted upon. + * @param string $op + * The operation to perform, e.g., 'enable' or 'disable'. * @param \Symfony\Component\HttpFoundation\Request $request * The current request. * - * @return array - * Render array. Table with current status of the ethereum node. Or just - * the server select form after initial submission. - * - * @throws \Exception - * If the server can not be loaded. + * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse + * Either returns a rebuilt listing page as an AJAX response, or redirects + * back to the listing page. */ - public function status($server_id = NULL, Request $request) { - // Used to tell if the server select form was submitted. - $form_id = $request->request->get('form_id'); - // If the server select form was submitted, we don't need to build the - // report because it will be built once the form redirect is complete. - // But we do need to build the form again otherwise it doesn't process. - if ($form_id && $form_id == 'ethereum_status_server_select_form') { - $server_id = $request->attributes->get('server_id'); - return ['choose_server' => \Drupal::formBuilder()->getForm('Drupal\ethereum\Form\EthereumStatusServerSelectForm', $server_id)]; + public function performOperation(EthereumServerInterface $ethereum_server, $op, Request $request) { + // Perform the operation. + $ethereum_server->$op()->save(); + + // If the request is via AJAX, return the rendered list as JSON. + if ($request->request->get('js')) { + $list = $this->entityTypeManager()->getListBuilder('ethereum_server')->render(); + $response = new AjaxResponse(); + $response->addCommand(new ReplaceCommand('#ethereum-server-list', $list)); + return $response; } - if ($server_id) { - try { - $server = \Drupal::service('ethereum.manager')->getServer($server_id); - $host = $server->get('url'); - $this->web3 = new Ethereum($host); - } - catch (\Exception $e) { - \Drupal::logger('ethereum')->error($e->getMessage()); - return [ - '#markup' => $e->getMessage(), - ]; - } - } - else { - // Load the server. - $server = \Drupal::service('ethereum.manager')->getCurrentServer(); - } - - // Validate the server. - $liveStatus = $server->validateConnection(); - $this->messenger()->addMessage( - $liveStatus['message'], ($liveStatus['error']) ? 'error' : 'status' - ); - - // Config info. - $serverInfo = [ - '#type' => 'fieldset', - '#title' => $this->t('Ethereum connection'), - 'current_server' => $this->getServerInfoAsTable($server), - ]; - - if (!$liveStatus['error']) { - - // Get Live status. - $status_rows[] = [$this->t("Client version (web3_clientVersion)"), $this->web3->web3_clientVersion()->val()]; - $status_rows[] = [$this->t("Listening (net_listening)"), $this->web3->net_listening()->val() ? '✔' : '✘']; - $status_rows[] = [$this->t("Peers (net_peerCount)"), $this->web3->net_peerCount()->val()]; - $status_rows[] = [$this->t("Protocol version (eth_protocolVersion)"), $this->web3->eth_protocolVersion()->val()]; - - $status_rows[] = [$this->t("Network version (net_version)"), $this->web3->net_version()->val()]; - $status_rows[] = [$this->t("Syncing (eth_syncing)"), $this->web3->eth_syncing()->val() ? '✔' : '✘']; - - // Mining and Hashrate. - $status_rows[] = [$this->t("Mining (eth_mining)"), $this->web3->eth_mining()->val() ? '✔' : '✘']; - - $hash_rate = $this->web3->eth_hashrate(); - $mining = is_a($hash_rate, 'EthQ') ? ((int) ($hash_rate->val() / 1000) . ' KH/s') : '✘'; - $status_rows[] = [$this->t("Mining hashrate (eth_hashrate)"), $mining]; - - // Gas price is returned in WEI. See: http://ether.fund/tool/converter. - $price = $this->web3->eth_gasPrice()->val(); - $price = $price . 'wei ( ≡ ' . number_format(($price / 1000000000000000000), 8, '.', '') . ' Ether)'; - $status_rows[] = [$this->t("Current price per gas in wei (eth_gasPrice)"), $price]; - - // Accounts. - $status_rows[] = [$this->t("Accounts info"), '']; - $coin_base = $this->web3->eth_coinbase()->hexVal(); - if ($coin_base === '0x0000000000000000000000000000000000000000') { - $coin_base = 'No coinbase available at this network node.'; - } - $status_rows[] = [$this->t("Coinbase (eth_coinbase)"), $coin_base]; - $address = array(); - - foreach ($this->web3->eth_accounts() as $addr) { - $address[] = $addr->hexVal(); - } - $status_rows[] = [$this->t("Accounts (eth_accounts)"), implode(', ', $address)]; - - $serverLiveInfo = [ - '#type' => 'fieldset', - '#title' => $this->t('Ethereum node live status.'), - 'server_status' => [ - 'table' => [ - '#theme' => 'table', - '#rows' => $status_rows, - ] - ] - ]; - - $random_rows[] = [$this->t('JsonRPC standard Methods'), $this->t('Read more about Ethereum JsonRPC-API implementation.')]; - $random_rows[] = [$this->t('Ethereum-PHP'), $this->t('Ethereum Web3 PHP API reference and codebase.')]; - - // Blocks. - $random_rows[] = [$this->t("Block info"), '']; - $block_latest = $this->web3->eth_getBlockByNumber(new EthBlockParam('latest'), new EthB(FALSE)); - $random_rows[] = [ - $this->t("Latest block age"), - \Drupal::service('date.formatter')->format($block_latest->getProperty('timestamp'), 'html_datetime'), - ]; - // Testing_only. - - $block_earliest = $this->web3->eth_getBlockByNumber(new EthBlockParam('earliest'), new EthB(FALSE)); - $random_rows[] = [ - $this->t("Age of 'earliest' block
The 'earliest' block has no timestamp on many networks."), - \Drupal::service('date.formatter')->format($block_earliest->getProperty('timestamp'), 'html_datetime'), - ]; - $random_rows[] = [ - $this->t("Client first (eth_getBlockByNumber('earliest'))"), - Markup::create('
' . $this->web3->debug('', $block_earliest) . '
'), - ]; - - // Second param will return TX hashes instead of full TX. - $block_latest = $this->web3->eth_getBlockByNumber(new EthBlockParam('latest'), new EthB(FALSE)); - $random_rows[] = [ - $this->t("Client first (eth_getBlockByNumber('latest'))"), - Markup::create('
' . $this->web3->debug('', $block_latest) . '
'), - ]; - $random_rows[] = [ - $this->t("Uncles of latest block"), - Markup::create('
' . $this->web3->debug('', $block_latest->getProperty('uncles')) . '
'), - ]; - $highBlockNumber = 999999999; - $high_block = $this->web3->eth_getBlockByNumber(new EthBlockParam($highBlockNumber), new EthB(FALSE)); - $high_block = !is_null($high_block) ? $high_block->getProperty('hash') : 'Block ' . $highBlockNumber . ' is null.'; - $random_rows[] = [ - $this->t("Get hash of a high block number
Might be empty"), - $high_block, - ]; - - // More. - - // Ethereum sha3 != standardized sha3, but a "Keccak-256" - // @see https://ethereum.stackexchange.com/a/554/852 - $random_rows[] = [ - $this->t("web3_sha3('testing')"), - $this->web3->sha3('testing'), - ]; - - // NON standard JsonRPC-API Methods below. - $random_rows[] = [$this->t('Non standard methods'), $this->t('PHP Ethereum controller API provides additional methods. They are part of the Ethereum PHP library, but not part of JsonRPC-API standard.')]; - $random_rows[] = [$this->t("getMethodSignature('validateUserByHash(bytes32)')"), $this->web3->getMethodSignature('validateUserByHash(bytes32)')]; - - $serverRandomRows = [ - '#type' => 'fieldset', - '#title' => $this->t('Random stuff.'), - 'server_status' => [ - 'table' => [ - '#theme' => 'table', - '#rows' => $random_rows, - ] - ] - ]; - } - - - - // Debug output for all calls since last call of - // $this->debug() or $this->debug(TRUE). - // $this->debug(); - - return [ - 'choose_server' => \Drupal::formBuilder()->getForm('Drupal\ethereum\Form\EthereumStatusServerSelectForm', $server_id), - 'server_info' => isset($serverInfo) ? $serverInfo : null, - 'server_live_status' => isset($serverLiveInfo) ? $serverLiveInfo : null, - 'random_stuff' => isset($serverRandomRows) ? $serverRandomRows : null, - ]; + // Otherwise, redirect back to the network settings page. + return $this->redirect('ethereum.settings'); } - /** - * Server info as render Array Table. - * - * @param $server EthereumServerInterface - * Server config entity. - * - * @return array - * Table render array. - */ - public function getServerInfoAsTable(EthereumServerInterface $server) { - $networks = \Drupal::service('ethereum.manager')->getAllNetworks(); - $currentNet = $networks[$server->get('network_id')]; - - $formElement = array( - '#type' => 'table', - ); - $formElement['info'] = [ - 'label' => array('#markup' => 'Node info'), - 'content' => [ - '#markup' => $server->label() . '
' . '' . $server->get('description'). '', - ], - ]; - $formElement['config_id'] = [ - 'label' => array('#markup' => 'Config name'), - 'content' => [ - '#markup' => $server->id(), - ], - ]; - $formElement['url'] = [ - 'label' => array('#markup' => 'RPC Url'), - 'content' => ['#markup' => $server->get('url')], - ]; - $formElement['network'] = [ - 'label' => array('#markup' => 'Network info'), - 'content' => [ - '#markup' => - '' . $currentNet['label'] . ' (Ethereum Network Id: ' . $currentNet['id'] . ')
' - . $currentNet['description'] . '
' - ], - ]; - - if (isset($currentNet['link_to_address'])) { - $formElement['explorer'] = [ - 'label' => array('#markup' => 'Blockchain Explorer'), - 'content' => [ - '#markup' => $currentNet['link_to_address'] - ] - ]; - } - - return $formElement; - } } diff --git a/src/Controller/EthereumStatusPageController.php b/src/Controller/EthereumStatusPageController.php new file mode 100644 index 0000000..7b0f0c6 --- /dev/null +++ b/src/Controller/EthereumStatusPageController.php @@ -0,0 +1,257 @@ +request->get('form_id'); + // If the server select form was submitted, we don't need to build the + // report because it will be built once the form redirect is complete. + // But we do need to build the form again otherwise it doesn't process. + if ($form_id && $form_id == 'ethereum_status_server_select_form') { + $server_id = $request->attributes->get('server_id'); + return ['choose_server' => \Drupal::formBuilder()->getForm('Drupal\ethereum\Form\EthereumStatusServerSelectForm', $server_id)]; + } + if ($server_id) { + try { + $server = \Drupal::service('ethereum.manager')->getServer($server_id); + $host = $server->get('url'); + $this->web3 = new Ethereum($host); + } + catch (\Exception $e) { + \Drupal::logger('ethereum')->error($e->getMessage()); + return [ + '#markup' => $e->getMessage(), + ]; + } + } + else { + // Load the server. + $server = \Drupal::service('ethereum.manager')->getCurrentServer(); + } + + // Validate the server. + $liveStatus = $server->validateConnection(); + $this->messenger()->addMessage( + $liveStatus['message'], ($liveStatus['error']) ? 'error' : 'status' + ); + + // Config info. + $serverInfo = [ + '#type' => 'fieldset', + '#title' => $this->t('Ethereum connection'), + 'current_server' => $this->getServerInfoAsTable($server), + ]; + + if (!$liveStatus['error']) { + + // Get Live status. + $status_rows[] = [$this->t("Client version (web3_clientVersion)"), $this->web3->web3_clientVersion()->val()]; + $status_rows[] = [$this->t("Listening (net_listening)"), $this->web3->net_listening()->val() ? '✔' : '✘']; + $status_rows[] = [$this->t("Peers (net_peerCount)"), $this->web3->net_peerCount()->val()]; + $status_rows[] = [$this->t("Protocol version (eth_protocolVersion)"), $this->web3->eth_protocolVersion()->val()]; + + $status_rows[] = [$this->t("Network version (net_version)"), $this->web3->net_version()->val()]; + $status_rows[] = [$this->t("Syncing (eth_syncing)"), $this->web3->eth_syncing()->val() ? '✔' : '✘']; + + // Mining and Hashrate. + $status_rows[] = [$this->t("Mining (eth_mining)"), $this->web3->eth_mining()->val() ? '✔' : '✘']; + + $hash_rate = $this->web3->eth_hashrate(); + $mining = is_a($hash_rate, 'EthQ') ? ((int) ($hash_rate->val() / 1000) . ' KH/s') : '✘'; + $status_rows[] = [$this->t("Mining hashrate (eth_hashrate)"), $mining]; + + // Gas price is returned in WEI. See: http://ether.fund/tool/converter. + $price = $this->web3->eth_gasPrice()->val(); + $price = $price . 'wei ( ≡ ' . number_format(($price / 1000000000000000000), 8, '.', '') . ' Ether)'; + $status_rows[] = [$this->t("Current price per gas in wei (eth_gasPrice)"), $price]; + + // Accounts. + $status_rows[] = [$this->t("Accounts info"), '']; + $coin_base = $this->web3->eth_coinbase()->hexVal(); + if ($coin_base === '0x0000000000000000000000000000000000000000') { + $coin_base = 'No coinbase available at this network node.'; + } + $status_rows[] = [$this->t("Coinbase (eth_coinbase)"), $coin_base]; + $address = array(); + + foreach ($this->web3->eth_accounts() as $addr) { + $address[] = $addr->hexVal(); + } + $status_rows[] = [$this->t("Accounts (eth_accounts)"), implode(', ', $address)]; + + $serverLiveInfo = [ + '#type' => 'fieldset', + '#title' => $this->t('Ethereum node live status.'), + 'server_status' => [ + 'table' => [ + '#theme' => 'table', + '#rows' => $status_rows, + ] + ] + ]; + + $random_rows[] = [$this->t('JsonRPC standard Methods'), $this->t('Read more about Ethereum JsonRPC-API implementation.')]; + $random_rows[] = [$this->t('Ethereum-PHP'), $this->t('Ethereum Web3 PHP API reference and codebase.')]; + + // Blocks. + $random_rows[] = [$this->t("Block info"), '']; + $block_latest = $this->web3->eth_getBlockByNumber(new EthBlockParam('latest'), new EthB(FALSE)); + $random_rows[] = [ + $this->t("Latest block age"), + \Drupal::service('date.formatter')->format($block_latest->getProperty('timestamp'), 'html_datetime'), + ]; + + // Testing_only. + + $block_earliest = $this->web3->eth_getBlockByNumber(new EthBlockParam('earliest'), new EthB(FALSE)); + $random_rows[] = [ + $this->t("Age of 'earliest' block
The 'earliest' block has no timestamp on many networks."), + \Drupal::service('date.formatter')->format($block_earliest->getProperty('timestamp'), 'html_datetime'), + ]; + $random_rows[] = [ + $this->t("Client first (eth_getBlockByNumber('earliest'))"), + Markup::create('
' . $this->web3->debug('', $block_earliest) . '
'), + ]; + + // Second param will return TX hashes instead of full TX. + $block_latest = $this->web3->eth_getBlockByNumber(new EthBlockParam('latest'), new EthB(FALSE)); + $random_rows[] = [ + $this->t("Client first (eth_getBlockByNumber('latest'))"), + Markup::create('
' . $this->web3->debug('', $block_latest) . '
'), + ]; + $random_rows[] = [ + $this->t("Uncles of latest block"), + Markup::create('
' . $this->web3->debug('', $block_latest->getProperty('uncles')) . '
'), + ]; + $highBlockNumber = 999999999; + $high_block = $this->web3->eth_getBlockByNumber(new EthBlockParam($highBlockNumber), new EthB(FALSE)); + $high_block = !is_null($high_block) ? $high_block->getProperty('hash') : 'Block ' . $highBlockNumber . ' is null.'; + $random_rows[] = [ + $this->t("Get hash of a high block number
Might be empty"), + $high_block, + ]; + + // More. + + // Ethereum sha3 != standardized sha3, but a "Keccak-256" + // @see https://ethereum.stackexchange.com/a/554/852 + $random_rows[] = [ + $this->t("web3_sha3('testing')"), + $this->web3->sha3('testing'), + ]; + + // NON standard JsonRPC-API Methods below. + $random_rows[] = [$this->t('Non standard methods'), $this->t('PHP Ethereum controller API provides additional methods. They are part of the Ethereum PHP library, but not part of JsonRPC-API standard.')]; + $random_rows[] = [$this->t("getMethodSignature('validateUserByHash(bytes32)')"), $this->web3->getMethodSignature('validateUserByHash(bytes32)')]; + + $serverRandomRows = [ + '#type' => 'fieldset', + '#title' => $this->t('Random stuff.'), + 'server_status' => [ + 'table' => [ + '#theme' => 'table', + '#rows' => $random_rows, + ] + ] + ]; + } + + + + // Debug output for all calls since last call of + // $this->debug() or $this->debug(TRUE). + // $this->debug(); + + return [ + 'choose_server' => \Drupal::formBuilder()->getForm('Drupal\ethereum\Form\EthereumStatusServerSelectForm', $server_id), + 'server_info' => isset($serverInfo) ? $serverInfo : null, + 'server_live_status' => isset($serverLiveInfo) ? $serverLiveInfo : null, + 'random_stuff' => isset($serverRandomRows) ? $serverRandomRows : null, + ]; + } + + /** + * Server info as render Array Table. + * + * @param $server EthereumServerInterface + * Server config entity. + * + * @return array + * Table render array. + */ + public function getServerInfoAsTable(EthereumServerInterface $server) { + $networks = \Drupal::service('ethereum.manager')->getAllNetworks(); + $currentNet = $networks[$server->get('network_id')]; + + $formElement = array( + '#type' => 'table', + ); + $formElement['info'] = [ + 'label' => array('#markup' => 'Node info'), + 'content' => [ + '#markup' => $server->label() . '
' . '' . $server->get('description'). '', + ], + ]; + $formElement['config_id'] = [ + 'label' => array('#markup' => 'Config name'), + 'content' => [ + '#markup' => $server->id(), + ], + ]; + $formElement['url'] = [ + 'label' => array('#markup' => 'RPC Url'), + 'content' => ['#markup' => $server->get('url')], + ]; + $formElement['network'] = [ + 'label' => array('#markup' => 'Network info'), + 'content' => [ + '#markup' => + '' . $currentNet['label'] . ' (Ethereum Network Id: ' . $currentNet['id'] . ')
' + . $currentNet['description'] . '
' + ], + ]; + + if (isset($currentNet['link_to_address'])) { + $formElement['explorer'] = [ + 'label' => array('#markup' => 'Blockchain Explorer'), + 'content' => [ + '#markup' => $currentNet['link_to_address'] + ] + ]; + } + + return $formElement; + } +} diff --git a/src/Controller/EthereumUIController.php b/src/Controller/EthereumUIController.php deleted file mode 100644 index eb5a94a..0000000 --- a/src/Controller/EthereumUIController.php +++ /dev/null @@ -1,46 +0,0 @@ -$op()->save(); - - // If the request is via AJAX, return the rendered list as JSON. - if ($request->request->get('js')) { - $list = $this->entityTypeManager()->getListBuilder('ethereum_server')->render(); - $response = new AjaxResponse(); - $response->addCommand(new ReplaceCommand('#ethereum-server-list', $list)); - return $response; - } - - // Otherwise, redirect back to the page. - return $this->redirect('entity.ethereum_server.collection'); - } - -} diff --git a/src/Entity/EthereumServer.php b/src/Entity/EthereumServer.php index cfc606e..94df3c7 100644 --- a/src/Entity/EthereumServer.php +++ b/src/Entity/EthereumServer.php @@ -5,7 +5,6 @@ use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\ethereum\EthereumServerInterface; -use Ethereum\Ethereum; /** * Defines the EthereumServer entity.